2010-08-27 13 views
10

Primero, this question ayudó mucho a seguir el camino correcto para trabajar con el control de versiones de datos del núcleo. Así que agregué una nueva versión para mi modelo, y ahora estoy intentando que funcione la migración automática, pero tengo un problema. ¡No puedo recordar cómo era mi versión anterior! Intento ejecutar la aplicación en mi teléfono, pero he estado usando el simulador por un tiempo e hice algunos cambios en el esquema. La versión en el teléfono es de hace bastante tiempo. Así que cada vez que trato de modificar la versión anterior a lo que creo que está en el teléfono, sigo teniendo el error "No puedo encontrar el modelo para la tienda de origen". Supongo que es porque tengo el viejo esquema equivocado.datos básicos no se puede encontrar el modelo para la tienda de origen, ¿cómo era mi tienda anterior?

¿Hay alguna forma de que yo sepa cómo es el esquema en el teléfono? Salvo eso, ¿cómo podría simplemente borrar la tienda sqlite del teléfono para poder comenzar de nuevo desde la versión 1?

+9

Usted puede simplemente eliminar la aplicación para el teléfono y vuelva a instalar y se obtiene una aplicación fresca y por lo tanto una tienda sqlite fresca – thelaws

Respuesta

5

El mensaje de error significa que no puede encontrar el archivo de modelo compilado .mom para la tienda existente. Core Data está buscando la versión exacta de .mom que configuró la tienda. El archivo .mom dice a los Datos principales cómo mapear los datos serializados en el archivo en objetos. Sin ese archivo modelo, no se sabe cómo migrar la tienda al nuevo modelo porque no sabe qué datos corresponden a cada entidad o propiedad de la entidad.

Solo he visto esto una vez y la causa de IIRC fue que el nuevo archivo .mom tenía exactamente el mismo nombre y ubicación que el anterior. Cuando se actualizó la aplicación, se sobrescribió el antiguo archivo .mom.

Intente cambiar el nombre del nuevo archivo de modelo y vea si eso ayuda. De lo contrario, probablemente necesitaremos más detalles sobre lo que está haciendo.

+0

Para cualquier otra persona atrapados en este problema por favor tome nota: el nombre de la carpeta momd cedes pathForResource distingue entre mayúsculas y minúsculas. – bizsytes

0

Tuve el mismo problema también. Lo resolví borrando mi antigua base de datos y construyendo el proyecto nuevamente. No estoy seguro de que esta sea la manera correcta de hacerlo. Aparentemente apunta al archivo de base de datos incorrecto. En mi caso, estaba creando un proyecto simple usando datos básicos y estaba probando la migración. Cuando creé un nuevo modelo con una columna adicional y construí mi proyecto, había 2 archivos: coreData.sqlite y coreData ~ .sqlite ... Entonces, lo que siento es que la base de datos equivocada es señalada y, por lo tanto, el error. Cuando borré la base de datos y volví a construir el proyecto, funcionó perfectamente para mí.

Si elimina la base de datos, sería mejor guardar una copia de la base de datos en otra ubicación para que no la pierda.

+1

La mejor manera es borrar la aplicación del teléfono. generará una nueva base de datos sqlite cuando reinstale la aplicación la próxima vez que se inicie el simulador. – emdog4

13

Me estaba arrancando el pelo por el error "No se puede encontrar el modelo para la tienda de origen" durante todo un día. Aquí es una elaboración de la respuesta de learner2010 para que los Googlers: Modelo de hash

  • Su base de datos SQLite debe coincidir con uno de la mamá o momd creado por su xcdatamodel cuando se genera la aplicación. Puede ver los valores hash en el VersionInfo.plist de momd en el paquete de la aplicación creada. Vea a continuación el código para encontrar el hash de modelo de su base de datos.

  • Así que si cambia su xcdatamodel en lugar de crear una nueva versión en Xcode-> Editor-> Agregar versión de modelo ... entonces el hash de su modelo será diferente, y addPersistentStoreWithType no podrá usar su base de datos anterior , que usó el viejo modelo. Eso es lo que causa el error "No se puede encontrar el modelo para la tienda de origen".

  • Para empeorar las cosas, la base de datos sqlite se almacena en algo como "/ private/var/mobile/Library/Mobile Documents/YOU_APP_ID/Data.nosync/YOUR_DB.sqlite" y esto puede mantenerse incluso si elimina la aplicación desde el dispositivo y vuelva a instalarlo! Entonces pensarás que hay algo mal con tu código, cuando en realidad solo tienes una base de datos obsoleta que necesita ser eliminada.Por lo general, esto ocurre durante la depuración, por lo que no hay datos reales de todos modos.

  • Por lo tanto, el flujo de trabajo adecuado para permitir migraciones en el futuro es hacer su modelo, ejecutar su aplicación para construir la base de datos y luego crear NUEVAS VERSIONES del modelo cada vez que necesite realizar cambios. Todo "solo funcionará" si mantiene los cambios menores. Luego, cuando esté listo para lanzar su aplicación, seleccione el modelo final y elimine el resto. A continuación, elimine su base de datos de "/ private/var/mobile/Library/Mobile Documents". Luego, en versiones futuras, incluya todos los modelos de versiones anteriores junto con su modelo más reciente (si ha cambiado) y los usuarios podrán migrar cada vez.

Aquí está mi código hasta ahora. La línea importante es:

[fileManager removeItemAtPath:iCloudData error:&error]; 

Pero solo se utilizará durante la depuración para eliminar su base de datos anterior. Aquí está el código de producción en AppDelegate.m:

- (NSManagedObjectModel *)managedObjectModel 
{ 
    if (__managedObjectModel != nil) 
    { 
     return __managedObjectModel; 
    } 
    //NSURL *modelURL = [[NSBundle mainBundle] URLForResource:@"Model" withExtension:@"momd"]; 
    //__managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL]; 

    //NSArray *testArray = [[NSBundle mainBundle] URLsForResourcesWithExtension:@"momd"subdirectory:nil]; 

    NSString *path = [[NSBundle mainBundle] pathForResource:@"Model" ofType:@"momd"]; 

    if(!path) path = [[NSBundle mainBundle] pathForResource:@"Model" ofType:@"mom"]; 

    NSURL *modelURL = [NSURL fileURLWithPath:path]; 

    __managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL]; 

    //__managedObjectModel = [NSManagedObjectModel mergedModelFromBundles:nil]; 

    return __managedObjectModel; 
} 

- (NSPersistentStoreCoordinator *)persistentStoreCoordinator 
{ 
    if((__persistentStoreCoordinator != nil)) { 
     return __persistentStoreCoordinator; 
    } 

    __persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel: [self managedObjectModel]];  
    NSPersistentStoreCoordinator *psc = __persistentStoreCoordinator; 

    // Set up iCloud in another thread: 

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 

     // ** Note: if you adapt this code for your own use, you MUST change this variable: 
     NSString *iCloudEnabledAppID = @"RW6RS7HS69.com.zsculpt.soaktest"; 

     // ** Note: if you adapt this code for your own use, you should change this variable:   
     NSString *dataFileName = @"mydailysoak.sqlite"; 

     // ** Note: For basic usage you shouldn't need to change anything else 

     NSString *iCloudDataDirectoryName = @"Data.nosync"; 
     NSString *iCloudLogsDirectoryName = @"Logs"; 
     NSFileManager *fileManager = [NSFileManager defaultManager];   
     NSURL *localStore = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:dataFileName]; 
     NSURL *iCloud = [fileManager URLForUbiquityContainerIdentifier:nil]; 

     if (iCloud) { 

      NSLog(@"iCloud is working"); 

      NSURL *iCloudLogsPath = [NSURL fileURLWithPath:[[iCloud path] stringByAppendingPathComponent:iCloudLogsDirectoryName]]; 

      NSLog(@"iCloudEnabledAppID = %@",iCloudEnabledAppID); 
      NSLog(@"dataFileName = %@", dataFileName); 
      NSLog(@"iCloudDataDirectoryName = %@", iCloudDataDirectoryName); 
      NSLog(@"iCloudLogsDirectoryName = %@", iCloudLogsDirectoryName); 
      NSLog(@"iCloud = %@", iCloud); 
      NSLog(@"iCloudLogsPath = %@", iCloudLogsPath); 

      if([fileManager fileExistsAtPath:[[iCloud path] stringByAppendingPathComponent:iCloudDataDirectoryName]] == NO) { 
       NSError *fileSystemError; 
       [fileManager createDirectoryAtPath:[[iCloud path] stringByAppendingPathComponent:iCloudDataDirectoryName] 
        withIntermediateDirectories:YES 
            attributes:nil 
              error:&fileSystemError]; 
       if(fileSystemError != nil) { 
        NSLog(@"Error creating database directory %@", fileSystemError); 
       } 
      } 

      NSString *iCloudData = [[[iCloud path] 
            stringByAppendingPathComponent:iCloudDataDirectoryName] 
            stringByAppendingPathComponent:dataFileName]; 

      NSLog(@"iCloudData = %@", iCloudData); 

      NSMutableDictionary *options = [NSMutableDictionary dictionary]; 
      [options setObject:[NSNumber numberWithBool:YES] forKey:NSMigratePersistentStoresAutomaticallyOption]; 
      [options setObject:[NSNumber numberWithBool:YES] forKey:NSInferMappingModelAutomaticallyOption]; 
      [options setObject:iCloudEnabledAppID   forKey:NSPersistentStoreUbiquitousContentNameKey]; 
      [options setObject:iCloudLogsPath    forKey:NSPersistentStoreUbiquitousContentURLKey]; 

      [psc lock]; 
     NSError *error; 

      [psc addPersistentStoreWithType:NSSQLiteStoreType 
           configuration:nil 
             URL:[NSURL fileURLWithPath:iCloudData] 
            options:options 
             error:&error]; 

      if(error) 
      { 
       NSLog(@"Error adding persistent store %@, %@", error, [error userInfo]); 

       // comment in this line while debugging if get "Can't find model for source store" error in addPersistentStoreWithType. 
       // it means the sqlite database doesn't match the new model and needs to be created from scratch. 
       // this happens if you change the xcdatamodel instead of creating a new one under Xcode->Editor->Add Model Version... 
       // CoreData can only automatically migrate if there is a new model version (it can't migrate if the model simply changes, because it can't see the difference between the two models). 
       // be sure to back up the database if needed, because all data will be lost. 
       //[fileManager removeItemAtPath:iCloudData error:&error]; 

       /*// this is another way to verify the hashes for the database's model to make sure they match one of the entries in the momd directory's VersionInfo.plist 
       NSDictionary *sourceMetadata = [NSPersistentStoreCoordinator metadataForPersistentStoreOfType:NSSQLiteStoreType URL:[NSURL fileURLWithPath:iCloudData] error:&error]; 

       if(!sourceMetadata) 
        NSLog(@"sourceMetadata is nil"); 
       else 
        NSLog(@"sourceMetadata is %@", sourceMetadata);*/ 
      } 

      [psc unlock]; 
     } 
     else { 
      NSLog(@"iCloud is NOT working - using a local store"); 
      NSMutableDictionary *options = [NSMutableDictionary dictionary]; 
      [options setObject:[NSNumber numberWithBool:YES] forKey:NSMigratePersistentStoresAutomaticallyOption]; 
      [options setObject:[NSNumber numberWithBool:YES] forKey:NSInferMappingModelAutomaticallyOption]; 

      [psc lock]; 
     NSError *error; 

      [psc addPersistentStoreWithType:NSSQLiteStoreType 
           configuration:nil 
             URL:localStore 
            options:options 
             error:nil]; 

     if(error) 
      NSLog(@"Error adding persistent store %@, %@", error, [error userInfo]);  
      [psc unlock]; 
     } 

     dispatch_async(dispatch_get_main_queue(), ^{ 
      [[NSNotificationCenter defaultCenter] postNotificationName:@"SomethingChanged" object:self userInfo:nil]; 
     }); 
    }); 

    return __persistentStoreCoordinator; 
} 
+0

Para cualquier otra persona atascada en este problema, tenga en cuenta: ¡el nombre de la carpeta momd que usted proporciona en pathForResource distingue entre mayúsculas y minúsculas! – bizsytes

Cuestiones relacionadas