Implementación de “Migración liviana automática” para Core Data (iPhone)

Me gustaría hacer que mi aplicación sea capaz de realizar una migración ligera y automática cuando agregue nuevos atributos a mi modelo de datos principal.

En la guía de Apple esta es la única información sobre el tema que pude encontrar:

Migración liviana automática

Para solicitar una migración liviana automática, configure los indicadores adecuados en el diccionario de opciones que pase en addPersistentStoreWithType: configuration: URL: options: error :. Debe establecer los valores correspondientes a las claves NSMigratePersistentStoresAutomaticallyOption y NSInferMappingModelAutomaticallyOption en YES:

NSError *error; NSURL *storeURL = ; NSPersistentStoreCoordinator *psc = ; NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys: [NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption, [NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, nil]; if (![psc addPersistentStoreWithType: configuration: URL:storeURL options:options error:&error]) { // Handle the error. } 

Mi NSPersistentStoreCoordinator se inicializa de esta manera:

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

Tengo problemas para ver dónde y cómo debería agregar el código de Apple para que la Migración Ligera Automática funcione.

Esto es lo que hice para hacer Migración Ligera Automática (Fuente: http://brainwashinc.wordpress.com/2010/01/18/iphone-coredata-automatic-light-migration/ )

1. Establezca las opciones de Tienda persistente para la migración automática en el delegado de la aplicación.

Cambie su creación persistentStoreCoordinator a esto (reemplace 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. Versión de su modelo de datos y edite el nuevo archivo.

Seleccione su archivo xcdatamodel Diseño -> Modelo de datos -> Agregar versión de modelo (expanda su elemento xcdatamodeld) Seleccione el archivo “2” (o posterior), Diseño -> Modelo de datos -> Establecer versión actual (edite esta versión)

3. Especifique el recurso momd en el delegado de la aplicación.

Cambie su implementación de ManageObjectModel a esto (reemplace 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; } 

Al principio, la solución anterior no funcionó para mí. El managedObjectModel devuelto fue 0x0. Creo que esto se debe a que cambié el nombre de los archivos de los diferentes modelos. Si sigues las instrucciones de arriba a la letra, entonces todo funciona.

Sin embargo, si cambia los nombres de los archivos de modelos, puede seleccionar manualmente el archivo de modelo “actual”: Digamos que el archivo de modelo original era MYMODEL.xcdatamodel después de hacer el paso agregar modelo anterior que se convierte en un directorio MY.xcdatamodeld y debajo de él tiene MYMODEL.xcdatamodel y MYMODEL 2.xcdatamodel cambian el nombre del nuevo archivo de modelo a lo que desee, por ejemplo, digamos que quitó el espacio a MYMODEL2.xcdatamodel y editó su contenido. Ahora en el código de arriba, haz

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

Creo que esto se sum a la última respuesta.

Descubrí que el uso del recurso del paquete y los nombres .sqlite son realmente confusos al principio. ¿El nombre del recurso del paquete cambia con el cambio de versión? ¿El nombre .sqlite cambia? Ahora tengo mi migración funcionando, y aprendí que el nombre del modelo del paquete se refiere al nombre del directorio / carpeta en XCode que contiene todos los modelos, no el nombre de las versiones del modelo dentro de ese directorio.

Cuando le das un nombre de modelResource a:

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

Ese nombre de modelResource es el directorio / carpeta para los modelos en Xcode.

Cuando tu lo hagas:

  NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:storeFileName]; NSError *error = nil; if (![persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:options error:&error]) { // handle error } 

StoreFileName es el nombre de su archivo .sqlite en la carpeta Documentos / directorio ( no está en el paquete).

Además, cuando migra de una versión de modelo a otra versión de modelo, de forma predeterminada, el nombre de archivo .sqlite sigue siendo el mismo.

Oscar, en respuesta a tu problema, encontré lo mismo al principio. Sugeriría eliminar y volver a agregar el nuevo archivo .xcdatamodeld a su proyecto y luego reconstruirlo. ¡Espero que ayude!

Solución Swift 3

1. Establezca las opciones de Tienda persistente para la migración automática en el delegado de la aplicación.

Cambie su creación de persistentStoreCoordinator a esto (reemplace 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. Versión de su modelo de datos y edite el nuevo archivo.

Seleccione su archivo xcdatamodel Editor> Agregar versión de modelo: agregue un nombre para su nuevo modelo