web-dev-qa-db-fra.com

Mise en œuvre de la "migration légère automatique" pour Core Data (iPhone)

Je souhaite que mon application puisse effectuer une migration automatique légère en ajoutant nouveaux attributs à mon modèle de données de base.

Dans le guide d'Apple, c'est la seule information sur le sujet que j'ai pu trouver:

Migration automatique légère

Pour demander automatique léger migration, vous définissez les indicateurs appropriés dans le dictionnaire des options que vous transmettez addPersistentStoreWithType: configuration: URL: options: erreur: . Vous devez définir les valeurs correspondantes à la fois le NSMigratePersistentStoresAutomaticallyOption et le NSInferMappingModelAutomaticallyOption clés pour OUI:

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.
}

Ma NSPersistentStoreCoordinator est initialisée de la manière suivante:

- (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;
}

J'ai du mal à voir où et comment ajouter du code Apple pour que la migration automatique légère fonctionne?

49
RickiG

Voici ce que j'ai fait pour effectuer une migration automatique légère (Source: http://brainwashinc.wordpress.com/2010/01/18/iphone-coredata-automatic-light-migration/ )

1. Définissez les options du magasin persistant pour la migration automatique dans le délégué de l'application.

Changez votre création de persistentStoreCoordinator en ceci (remplacez 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. Versionnez votre modèle de données et modifiez le nouveau fichier.

Sélectionnez votre fichier xcdatamodelDesign -> Modèle de données -> Ajouter la version du modèle (développez votre élément xcdatamodeld) Sélectionnez le fichier «2 ″ (ou version ultérieure), Conception -> Modèle de données -> Définir la version actuelle version)

3. Spécifiez la ressource momd dans le délégué de l'application.

Changez votre implémentation managedObjectModel en ceci (remplace 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

Au début, la solution ci-dessus ne fonctionnait pas pour moi. ManagedObjectModel renvoyé était 0x0 . Je pense que c'est parce que j'ai renommé les noms de fichier des différents fichiers de modèle . Si vous suivez les instructions ci-dessus à la lettre, tout fonctionne.

Toutefois, si vous modifiez les noms de fichier de modèle, vous pouvez sélectionner manuellement le fichier de modèle "actuel": Supposons que votre fichier de modèle d'origine était MYMODEL.xcdatamodel Après avoir effectué l'étape d'ajout de modèle ci-dessus, il se transforme en un répertoire MY. xcdatamodeld et dessous, vous avez MYMODEL.xcdatamodel et MYMODEL 2.xcdatamodel renommer le nouveau fichier de modèle comme bon vous semble, par exemple, vous avez supprimé l’espace réservé à MYMODEL2.xcdatamodel et en éditer le contenu . Maintenant, dans le code ci-dessus, faites

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

Je pense que cela ajoute à la dernière réponse. 

J'ai trouvé l'utilisation de la ressource bundle et des noms .sqlite vraiment déroutante au début. Le nom de la ressource de l'ensemble change-t-il avec le changement de version? Le nom .sqlite change-t-il? Ma migration est en cours et j'ai appris que le nom de modèle de l'ensemble fait référence au nom du répertoire/dossier dans XCode contenant tous les modèles, et non au nom des versions de modèle de ce répertoire. 

Lorsque vous donnez un nom modelResource à:

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

Ce nom de modelResource est le répertoire/dossier des modèles dans Xcode.

Quand tu fais:

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

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

StoreFileName est le nom de votre fichier .sqlite dans le dossier/répertoire Documents (il s’agit de not dans l’ensemble).

De même, lorsque vous migrez d'une version de modèle à une autre version de modèle, le nom de fichier .sqlite reste par défaut identique.

1
Chris Prince

Solution Swift 3

1. Définissez les options du magasin persistant pour la migration automatique dans le délégué de l'application.

Changez votre création de persistentStoreCoordinator en ceci (remplace 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. Version de votre modèle de données et éditez le nouveau fichier.

Sélectionnez votre éditeur de fichier xcdatamodel> Ajouter une version de modèle - ajoutez un nom à votre nouveau modèle.

0
Ben Sullivan

Oscar, en réponse à ton problème, j'ai trouvé la même chose au départ. Je suggère de supprimer et d'ajouter de nouveau le nouveau fichier .xcdatamodeld à votre projet, puis de le reconstruire. J'espère que cela pourra aider! 

0
gemmakbarlow