En nuestra aplicación en desarrollo, estamos utilizando Core Data con una tienda de respaldo sqlite para almacenar nuestros datos. El modelo de objetos para nuestra aplicación es complejo. Además, la cantidad total de datos servidos por nuestra aplicación es demasiado grande para caber en un paquete de aplicaciones iOS (iPhone/iPad/iPod Touch). Debido al hecho de que nuestros usuarios, por lo general, solo están interesados en un subconjunto de los datos, hemos dividido nuestros datos de tal manera que la aplicación se envía con un subconjunto (aunque, ~ 100 MB) de los objetos de datos en el paquete de aplicaciones. Nuestros usuarios tienen la opción de descargar objetos de datos adicionales (de tamaño ~ 5 MB a 100 MB) de nuestro servidor después de que paguen los contenidos adicionales a través de las compras en la aplicación de iTunes. Los archivos de datos incrementales (existentes en las tiendas de respaldo sqlite) utilizan la misma versión xcdatamodel que los datos que se envían con el paquete; hay cero cambios en el modelo de objetos. Los archivos de datos incrementales se descargan de nuestro servidor como archivos sqlite con gzip. No queremos inflar nuestro paquete de aplicaciones enviando los contenidos incrementales con la aplicación. Además, no queremos confiar en las consultas sobre el servicio web (debido al complejo modelo de datos). Hemos probado la descarga de los datos sqlite incrementales de nuestro servidor. Hemos podido agregar el almacén de datos descargado al persistentStoreCoordinator compartido de la aplicación. ¿Cuál es una forma eficiente de combinar dos almacenes persistentes de datos centrales de iOS?
{
NSError *error = nil;
NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption,
[NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, nil];
if (![__persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:defaultStoreURL options:options error:&error])
{
NSLog(@"Failed with error: %@", [error localizedDescription]);
abort();
}
// Check for the existence of incrementalStore
// Add incrementalStore
if (incrementalStoreExists) {
if (![__persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:incrementalStoreURL options:options error:&error])
{
NSLog(@"Add of incrementalStore failed with error: %@", [error localizedDescription]);
abort();
}
}
}
Sin embargo, hay dos problemas con hacerlo de esta manera.
- recuperación de datos los resultados (por ejemplo, con NSFetchResultController) mostrará con los datos de la incrementalStoreURL añade al final de los datos de la defaultStoreURL.
- Algunos de los objetos están duplicados. Hay muchas entidades con datos de solo lectura en nuestro modelo de datos; estos se duplican cuando agregamos el segundo persistentStore al persistentStoreCoordinator.
Lo ideal sería que Core Data fusione los gráficos de objeto de las dos tiendas persistentes en una (no hay relaciones compartidas entre los datos de las dos tiendas en el momento de la descarga de datos). Además, nos gustaría eliminar los objetos duplicados. Al buscar en la Web, vimos un par de preguntas de personas que intentan hacer lo mismo que nosotros, como this answer y this answer. Hemos leído Marcus Zarra's blog on importing large data sets in Core Data. Sin embargo, ninguna de las soluciones que hemos visto funcionó para nosotros. No queremos leer y guardar manualmente los datos de la tienda incremental en la tienda predeterminada, ya que creemos que esto será muy lento y propenso a errores en el teléfono. ¿Hay una manera más eficiente de hacer la fusión?
Hemos intentado resolver el problema implementando una migración manual de la siguiente manera. Sin embargo, no hemos podido lograr que la fusión suceda con éxito. No estamos muy claros sobre la solución sugerida por las respuestas 1 y 2 mencionadas anteriormente. El blog de Marcus Zarra abordó algunos de los problemas que teníamos al principio de nuestro proyecto al importar nuestro gran conjunto de datos en iOS.
{
NSError *error = nil;
NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption,
[NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, nil];
NSMigrationManager *migrator = [[NSMigrationManager alloc] initWithSourceModel:__managedObjectModel destinationModel:__managedObjectModel];
if (![migrator migrateStoreFromURL:stateStoreURL
type:NSSQLiteStoreType
options:options
withMappingModel:nil
toDestinationURL:destinationStoreURL
destinationType:NSSQLiteStoreType
destinationOptions:nil
error:&error])
{
NSLog(@"%@", [error userInfo]);
abort();
}
}
Parece que el autor de respuesta 1 terminó la lectura de sus datos del almacén de incremento y guardar en el almacén predeterminado. Tal vez, hemos malentendido la solución sugerida por ambos artículos 1 & 2. El tamaño de nuestros datos puede impedirnos leer y volver a insertar manualmente nuestros datos incrementales en la tienda predeterminada. Mi pregunta es: ¿cuál es la forma más eficiente de obtener los gráficos de objetos de dos persistentStores (que tienen el mismo objectModel) para fusionarse en un persistentStore?
La migración automática funciona bastante bien cuando agregamos nuevos atributos de entidad a gráficos de objetos o modificamos relaciones. ¿Existe una solución simple para fusionar datos similares en la misma tienda persistente que será lo suficientemente resistente como para detenerse y reanudarse, ya que se realiza la migración automática?
¿Dónde está Marcus Zarra cuando lo necesito? He avanzado un poco usando el método [NSPersistentStore migratePersistentStore: toURL: options: withType: error]. Solo necesito un código de limpieza más para llegar a donde debo estar. – Sunny
Estoy luchando con lo mismo. ¿Puedes publicar lo que has propuesto hasta ahora? Estoy perdido. – damon
¡Hecho! Déjame saber cómo resulta para ti. – Sunny