it-swarm.com.de

Implementierung von "Automatic Lightweight Migration" für Core Data (iPhone)

Ich möchte, dass meine App eine automatische Migration durchführen kann, wenn ich meinem Kerndatenmodell Neue Attribute hinzufüge.

In der Anleitung von Apple ist dies die einzige Information zum Thema, die ich finden konnte:

Automatische leichte Migration

Um eine automatische Lightweight-Migration Anzufordern, setzen Sie im Optionswörterbuch, das Sie in Übergeben, entsprechende Flags . AddPersistentStoreWithType: Konfiguration: URL: Optionen: Fehler:. Sie benötigen zum Einstellen von Werten, die für die NSMigratePersistentStoresAutomaticallyOption und die NSInferMappingModelAutomaticallyOption - Taste zu JA entsprechen:

NSError *error;
NSURL *storeURL = <#The URL of a persistent store#>;
NSPersistentStoreCoordinator *psc = <#The coordinator#>;
NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
    [NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption,
    [NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, nil];

if (![psc addPersistentStoreWithType:<#Store type#>
    configuration:<#Configuration or nil#> URL:storeURL
    options:options error:&error]) {
    // Handle the error.
}

Meine NSPersistentStoreCoordinator wird auf diese Weise initialisiert:

- (NSPersistentStoreCoordinator *)persistentStoreCoordinator {

    if (persistentStoreCoordinator != nil) {
        return persistentStoreCoordinator;
    }

    NSURL *storeUrl = [NSURL fileURLWithPath: [[self applicationDocumentsDirectory] stringByAppendingPathComponent: @"FC.sqlite"]];

    NSError *error = nil;
    persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
    if (![persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeUrl options:nil error:&error]) {

        NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
        abort();
    }    

    return persistentStoreCoordinator;
}

Ich habe Probleme zu erkennen, wo und wie ich den Apple-Code hinzufügen sollte, damit die automatische Migration leicht funktioniert.

49
RickiG

Dies ist, was ich getan habe, um automatische leichte Migration zu machen (Quelle: http://brainwashinc.wordpress.com/2010/01/18/iphone-coredata-automatic-light-migration/ )

1. Legen Sie die Optionen für den permanenten Speicher für die automatische Migration im App-Delegaten fest.

Ändern Sie Ihre persistentStoreCoordinator-Erstellung in Folgendes (ersetzen Sie YOURDB):

- (NSPersistentStoreCoordinator *)persistentStoreCoordinator {

  if (persistentStoreCoordinator != nil) {
    return persistentStoreCoordinator;
  }

  NSURL *storeUrl = [NSURL fileURLWithPath: [[self applicationDocumentsDirectory] stringByAppendingPathComponent: @"YOURDB.sqlite"]];

  // handle db upgrade
  NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
  [NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption,
  [NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, nil];

  NSError *error = nil;
  persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel: [self managedObjectModel]];
  if (![persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeUrl options:options error:&error]) {
    // Handle error
  }

  return persistentStoreCoordinator;
}

2. Versionieren Sie Ihr Datenmodell und bearbeiten Sie die neue Datei.

Wählen Sie Ihre xcdatamodel-Datei aus Design -> Datenmodell -> Modellversion hinzufügen (erweitern Sie Ihr xcdatamodeld-Element) Wählen Sie die Datei "2" (oder höher), Design -> Data Model -> Set Current Version (diese Version bearbeiten)

3. Geben Sie die Momd-Ressource im App-Delegaten an.

Ändern Sie Ihre verwalteteObjectModel-Implementierung in diese (ersetzen Sie YOURDB).

- (NSManagedObjectModel *)managedObjectModel {

  if (managedObjectModel != nil) {
    return managedObjectModel;
  }

  NSString *path = [[NSBundle mainBundle] pathForResource:@"YOURDB" ofType:@"momd"];
  NSURL *momURL = [NSURL fileURLWithPath:path];
  managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:momURL];

  return managedObjectModel;
}
93
willi

Die obige Lösung funktionierte für mich zunächst nicht. Das zurückgegebene managedObjectModel war 0x0. Ich denke, das liegt daran, dass ich die Dateinamen der verschiedenen Modelldateien umbenannt habe. Wenn Sie die oben genannten Anweisungen befolgen, funktioniert alles.

Wenn Sie jedoch die Namen der Modelldateien ändern, können Sie die "aktuelle" Modelldatei manuell auswählen: Nehmen wir an, Ihre ursprüngliche Modelldatei war MYMODEL.xcdatamodel , Nachdem der oben genannte Schritt zum Hinzufügen des Modells ausgeführt wurde Ein Verzeichnis MY.xcdatamodeld und darunter haben Sie MYMODEL.xcdatamodel und MYMODEL 2.xcdatamodel . Benennen Sie die neue Modelldatei in das, was Sie möchten, beispielsweise sagen Sie, dass Sie den Speicherplatz in MYMODEL2.xcdatamodel entfernt haben und bearbeiten Sie den Inhalt. Nun im obigen Code

NSString *path = [mainBundle pathForResource:@"MYMODEL2" ofType:@"mom" inDirectory:@"MYMODEL.momd"];
7
udibr

Ich denke, das fügt die letzte Antwort hinzu. 

Ich fand die Verwendung der Bündelressource und der .sqlite-Namen auf den ersten Blick wirklich verwirrend. Ändert sich der Name der Bundle-Ressource mit der Versionsänderung? Ändert sich der .sqlite-Name? Ich habe nun meine Migration zum Laufen gebracht und erfahren, dass der Name des Bundle-Modells auf den Namen des Verzeichnisses/Ordners in XCode verweist, der alle Modelle enthält, nicht den Namen der Modellversionen in diesem Verzeichnis. 

Wenn Sie einen modelResource-Namen angeben:

NSURL *modelURL = [[NSBundle mainBundle] URLForResource:modelResource withExtension:@"momd"];
NSManagedObjectModel *theManagedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];

Dieser modelResource-Name ist das Verzeichnis/Ordner für die Modelle in Xcode.

Wenn Sie das tun:

    NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:storeFileName];
    NSError *error = nil;

    if (![persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:options error:&error]) {
        // handle error
    }

StoreFileName ist der Name Ihrer .sqlite-Datei im Ordner Documents/Verzeichnis (dies ist nicht im Bundle).

Wenn Sie von einer Modellversion zu einer anderen Modellversion migrieren, bleibt der Name der .sqlite-Datei standardmäßig derselbe.

1
Chris Prince

Swift 3 Lösung

1. Legen Sie die Optionen für den permanenten Speicher für die automatische Migration im App-Delegaten fest.

Ändern Sie Ihre persistentStoreCoordinator-Erstellung in diese (ersetzen Sie SingleViewCoreData.sqlite): 

lazy var persistentStoreCoordinator: NSPersistentStoreCoordinator = {


let coordinator: NSPersistentStoreCoordinator = NSPersistentStoreCoordinator(managedObjectModel: self.managedObjectModel)
let url = self.applicationDocumentsDirectory.appendingPathComponent("SingleViewCoreData.sqlite")

let options = [
  NSMigratePersistentStoresAutomaticallyOption : Int(true),
  NSInferMappingModelAutomaticallyOption : Int(true)
]

do {

  try coordinator.addPersistentStore(ofType: NSSQLiteStoreType, configurationName: nil, at: url, options: options)

} catch {

  print(error)
}

return coordinator

}()

2. Versionieren Sie Ihr Datenmodell und bearbeiten Sie die neue Datei.

Wählen Sie Ihre Xcdatamodel-Datei aus. Editor> Modellversion hinzufügen - geben Sie einen Namen für Ihr neues Modell ein

0
Ben Sullivan

Oskar, als Antwort auf Ihre Frage fand ich zunächst dasselbe. Ich würde vorschlagen, die neue .xcdatamodeld-Datei zu Ihrem Projekt zu löschen und erneut hinzuzufügen und dann neu zu erstellen. Hoffentlich hilft das! 

0
gemmakbarlow