2012-01-12 9 views
6

Estoy utilizando RestKit para tomar objetos de mi servicio RoR y utilizando CoreData para conservar algunos de los objetos (más objetos de tabla de búsqueda de tipo estático). TasteTag es uno de esos objetos persistido:Entidades de datos centrales anidadas cargadas en repositorios causan NSObjectInaccessibleException

#ifdef RESTKIT_GENERATE_SEED_DB 
    NSString *seedDatabaseName = nil; 
    NSString *databaseName = RKDefaultSeedDatabaseFileName; 
#else 
    NSString *seedDatabaseName = RKDefaultSeedDatabaseFileName; 
    NSString *databaseName = @"Model.sqlite"; 
#endif 

RKObjectManager* manager = [RKObjectManager objectManagerWithBaseURL:kServerURL]; 
manager.objectStore = [RKManagedObjectStore objectStoreWithStoreFilename:databaseName usingSeedDatabaseName:seedDatabaseName managedObjectModel:nil delegate:self]; 

.. lots of fun object mapping .. 

RKManagedObjectMapping* tasteTagMapping = [RKManagedObjectMapping mappingForClass:[TasteTag class]]; 
[tasteTagMapping mapKeyPath:@"id" toAttribute:@"tasteTagID"]; 
[tasteTagMapping mapKeyPath:@"name" toAttribute:@"name"]; 
tasteTagMapping.primaryKeyAttribute = @"tasteTagID"; 
[[RKObjectManager sharedManager].mappingProvider setMapping:tasteTagMapping forKeyPath:@"taste_tags"]; 
[[RKObjectManager sharedManager].mappingProvider addObjectMapping:tasteTagMapping]; 

.. some more mapping .. 

tengo los datos que llegan desde el servidor RoR y es cada vez asignan a los objetos como se esperaba. La entidad de Datos Básicos también parece corresponder bien después RestKit recibe la petición de vuelta:

"<TasteTag: 0x6e87170> (entity: TasteTag; id: 0x6e85d60 <x-coredata://03E4A20A-21F2-4A2D-92B4-C4424893D559/TasteTag/p5> ; data: <fault>)" 

El problema es cuando trato de acceder a las propiedades de los objetos de la falla parece que no puede haber fuego. Al principio me estaba llamando las propiedades, que siempre volvía como nula (a pesar de que disparará el fallo):

for (TasteTag *tag in self.vintage.tasteTags) { 
    [tagNames addObject:tag.name]; //get error of trying to add nil to array 
} 

Después de mirar en las fallas de activación manual (http://www.mlsite.net/blog/?p=518) intenté llamar [tag willAccessValueForKey:nil] que se traduce en:

Terminating app due to uncaught exception 'NSObjectInaccessibleException', reason: 'CoreData could not fulfill a fault for '0x6e7b060 <x-coredata://03E4A20A-21F2-4A2D-92B4-C4424893D559/TasteTag/p5>'' 

Al buscar la entidad en .sqlite en función de la clave (TasteTag/p5) se muestra asignada a la que yo esperaba.

Otras publicaciones relacionadas con RestKit recomiendan deshabilitar la caché de objetos (que no estoy usando) ya que esto generalmente es causado por una entidad que se está eliminando. Pero en esta etapa solo estoy leyendo, no borrando, y no tengo memoria caché en su lugar.

Si llamo al [TasteTag allObjects] puedo recuperar todos los objetos y se cargan sin problemas. Es solo en el caso cuando parecen tener una falla.

+0

Espero que encuentres una solución, estoy experimentando un problema casi idéntico. –

+0

@ryan si encuentra algo hágamelo saber, hasta ahora no he tenido suerte – Parrots

+0

@ryan - parece que no es específico de RestKit. Pregunta de seguimiento aquí: http://stackoverflow.com/questions/8856867/copying-objects-with-core-data-objects-in-them – Parrots

Respuesta

4

Documentando mi solución (léase: hack) según la sugerencia de Ryan.

El error parece estar en la forma en que RestKit supuso que usará los objetos devueltos desde su método objectLoader:didLoadObjects:. Parecen asumir que todo será respaldado por Core Data (y seguir el flujo similar a lo que Ryan mencionó: dejarlo sincronizar con Core Data, luego volver a consultarlo) o que usará todos los objetos no respaldados por Core Data y solo mantener esos resultados alrededor.

En mi caso, tenía una mezcla: una matriz raíz de objetos que no estaban respaldados por Core Data y que, a su vez, contenían una matriz de entidades respaldadas por Core Data. Los objetos de nivel superior son los que no me molestan en consultar al servidor y no tienen ninguna razón para persistir localmente más allá de la vista en la que se muestran. Parece que una vez objectLoader:didLoadObjects: se completa el contexto del objeto gestionado que respalda las entidades de Datos centrales dentro del objects Param se descarta (bajo la suposición de que volverá a consultarlos), haciendo que cualquier llamada futura a las entidades resulte en ser tratada como fallas, aunque no pueda desencadenar la falla y cargar los datos (resultados en NSObjectInaccessibleException).

Me salí con un hack feo - dentro de objectLoader:didLoadObjects: Acceder a uno de los contexto de objetos gestionados de la entidad de datos básicos y copiarlo en una propiedad dentro de la vista (self.context = [tag managedObjectContext];). Esto evita que el contexto se libere después de que se complete objectLoader:didLoadObjects:, lo que me permite acceder a las entidades sin problema más adelante en la vista.

Otra solución sería volver a consultar manualmente para cada entidad utilizando un nuevo contexto y copiar eso de nuevo a los objetos devueltos almacenados. Uno podría hacer esto cuando uno vaya a mostrarlos, o posiblemente algún postproceso en objectLoader:didLoadObjects:, usando un nuevo contexto. La ID de la entidad todavía se encuentra en el objeto con fallas, por lo que se podría usar para volver a consultar sin problemas incluso después de que el contexto original de RestKit desaparezca.Pero parece tonto tener que volver a consultar para cada entidad en el gráfico de objetos de esa manera.

+0

Puede desactivar la sincronización automática y almacenar objetos en su modelo de CD de forma manual cuando lo desee. ¡Pero necesito documentación sobre esto! Gracias de cualquier manera :) –

10

Encontré una solución que funcionó para mí (no estoy seguro de qué tan aplicable será para su situación, pero la estoy agregando como respuesta ya que resolvió este problema (o muy similar) para mí):

Hace un par de días, ejecuté el ejemplo RKTwitterCoreData y noté que funcionaba perfectamente mientras que el mío, con un código muy simple en este punto y haciendo casi lo mismo, no lo hacía. Obtuve un lote de fallas no realizadas. Así que decidí modificar todo mi código relacionado con RestKit para reflejar cómo lo hace el ejemplo RKTwitterCoreData.

Voy a dividir esto en trozos para tratar de ayudarte a seguir mi línea de pensamiento en ese momento (ya que no creo que nuestros problemas sean idénticos).

Mi original Asunción Implementación

Desde RestKit puede realizar copias de objetos de datos básicos, que supone que los objetos administrados podrían ser utilizados indistintamente. Por ejemplo, podría usar los objetos de Core Data de la misma manera que los recuperados de un servicio web remoto. Incluso podría unirlos para obtener todos los datos.

que estaba equivocado

Noté que RKTwitterCoreData 's código hizo no flujo de esta manera en lo más mínimo. Una parte decente de mi código coincidía con la de ellos, pero la mayor diferencia era que no trataban estos objetos como intercambiables. De hecho, ellos nunca utilizaron los objetos que obtuvieron de los almacenes de datos remotos.En cambio, simplemente dejan que "caiga por las grietas". Solo puedo suponer que significa que están agregados al almacén de datos de Core Data, ya que funciona para ellos y, ahora, para mí.

detalles

Mi aplicación trabajó después de modificar el código para utilizar este flujo. Solo entonces puedo conjeturar que las fallas no cumplibles que estamos viendo están relacionadas con el uso de los objetos respaldados por Core Data que obtenemos del servicio web. Si, en cambio, simplemente los ignora y luego realiza una búsqueda, recuperará todo (incluida la solicitud más reciente) y no obtendrá ninguna falla que no se pueda llenar.

Elaborar, si nos fijamos en RKTwitterViewController se dará cuenta de que las líneas 45-61 mango carga de objetos:

- (void)loadObjectsFromDataStore { 
    [_statuses release]; 
    NSFetchRequest* request = [RKTStatus fetchRequest]; 
    NSSortDescriptor* descriptor = [NSSortDescriptor sortDescriptorWithKey:@"createdAt" ascending:NO]; 
    [request setSortDescriptors:[NSArray arrayWithObject:descriptor]]; 
    _statuses = [[RKTStatus objectsWithFetchRequest:request] retain]; 
} 

- (void)loadData { 
    // Load the object model via RestKit  
    RKObjectManager* objectManager = [RKObjectManager sharedManager]; 
    [objectManager loadObjectsAtResourcePath:@"/status/user_timeline/RestKit" delegate:self block:^(RKObjectLoader* loader) { 
     // Twitter returns statuses as a naked array in JSON, so we instruct the loader 
     // to user the appropriate object mapping 
     loader.objectMapping = [objectManager.mappingProvider objectMappingForClass:[RKTStatus class]]; 
    }]; 
} 

todo se ve normal (al menos en comparación con cómo estaba esta carga inicialmente). Pero echar un vistazo al método objectLoader:didLoadObjects: delegado:

- (void)objectLoader:(RKObjectLoader*)objectLoader didLoadObjects:(NSArray*)objects { 
    [[NSUserDefaults standardUserDefaults] setObject:[NSDate date] forKey:@"LastUpdatedAt"]; 
    [[NSUserDefaults standardUserDefaults] synchronize]; 
    NSLog(@"Loaded statuses: %@", objects); 
    [self loadObjectsFromDataStore]; 
    [_tableView reloadData]; 
} 

La muestra ni siquiera toca el parámetro objects! (Aparte de la NSLog por supuesto ...)

Conclusión/tl; dr

No utilice los objetos gestionados que recibe de vuelta en objectLoader:didLoadObjects: como si estuvieran totalmente respaldadas por datos básicos. En cambio, ignórelos y vuelva a buscarlos desde Core Data. Todos los objetos, incluidos los de la última solicitud están allí. De lo contrario, obtendrás fallas que no se pueden llenar (al menos yo lo hice).

+0

Estaba llegando a la misma conclusión durante mi depuración. Parecen asumir que dejarás que se sincronice con el CD y luego volverás a consultar. El problema que tengo con eso es que no estaba planeando tener todos mis objetos respaldados por CD (no me interesa almacenarlos para más adelante, solo esta vista). Eso me obliga a usar los objetos devueltos. Terminé arreglando (léase: hackear de una manera fea) esto al retener el managedContext de NSManagedObject en viewController. Hacer eso me permite acceder a los objetos bien en cellForIndexPath. – Parrots

+0

Puede valer la pena agregarlo como respuesta para cualquier otro viajero desafortunado de esta faceta de RestKit. Estoy impresionado con la biblioteca, pero me parece extraño que esta advertencia no esté mejor documentada. –

+0

De acuerdo en la documentación. Realmente podría usar algunos documentos actualizados en lugar de los documentos más antiguos. Gracias por la información aquí. –

Cuestiones relacionadas