2010-01-05 11 views
28

Estoy haciendo una aplicación para iPhone que lee datos del archivo XML, los convierte en objetos administrados por Core Data y los guarda.Error críptico de Core Data: NSInvalidArgumentException, razón: referenceData64 solo se define para la clase abstracta

La aplicación funciona bien, principalmente, en un conjunto de datos/XML más pequeño que contiene ~ 150 objetos. Le dije todo porque el 10% de las veces, me gustaría obtener la siguiente excepción de CoreData al intentar salvar el contexto:

* Terminación de aplicación debido a excepción no detectada 'NSInvalidArgumentException', razón: '* -_referenceData64 solamente definido para la clase abstracta. Definir - [NSTemporaryObjectID_default _referenceData64]! '

En un conjunto de datos más grande (~ 2000), esto ocurre siempre, pero no en el mismo lugar. Podría fallar en el registro número 137, 580 o el último. Intenté mover el punto de guardado (por objeto, por cada 10 objetos, guardar una vez que todos los objetos estén asignados/iniciados) pero siempre toco la excepción anterior.

He buscado en Google la excepción y he visto a alguien que tiene los mismos problemas pero no ha visto ninguna resolución.

Mi siguiente paso consistiría en simplificar los objetos gestionados y las relaciones hasta un punto donde este error se detiene y crear desde allí para aislar el problema. El último recurso es deshacerse de Core Data y simplemente almacenar directamente en sqllite.

¡Gracias por toda su ayuda!

+0

¿Está utilizando alguna entidad abstracta en el modelo? –

+0

Hola Marcus, no usé entidades abstractas, pero estaba usando varios hilos y no me di cuenta de las reglas sobre el uso de datos centrales en hilos. – Brombie

+0

No estoy del todo seguro, pero me parece que tiene una entidad abstracta a la que intenta crear una instancia. ¿Puedes iluminarnos en la herencia? ¡Qué extraño mensaje de error! – beinstein

Respuesta

27

Tengo el mismo problema. Funciona para conjuntos de datos más pequeños, pero para conjuntos más grandes obtengo errores "_referenceData64 solo definidos para clases abstractas". No hay entidades abstractas en mi modelo.

EDIT:

creo que tengo esta resuelto. El problema en mi caso fue una confusión en mi parte re hilos. Estas son las pautas que seguí para solucionarlo:

  1. Analizo datos XML en una conversación. Al iniciar dicho hilo, cree un nuevo NSManagedObjectContext usando el mismo coordinador de tienda persistente que NSManagedObjectContext de su hilo principal.
  2. Cualquier objeto nuevo que hagas en el hilo se debe hacer para el NSManagedObjectContext de la secuencia. Si tiene que copiar objetos del NSManagedObjectContext del subproceso principal, copie el ID. Es decir.
    NSManagedObjectID *objectID = [foo objectID];
    FooClass *newFoo = [(FooClass*)[threadManagedObjectContext objectWithID:objectID] retain]
  3. Al finalizar el análisis, debe guardar los cambios realizados en el NSManagedObjectContext de la secuencia. Debe bloquear el coordinador de tienda persistente. He utilizado el siguiente (código incompleto):

`

- (void)onFinishParsing { 
    // lock the store we share with main thread's context 
    [persistentStoreCoordinator lock]; 

    // save any changes, observe it so we can trigger merge with the actual context 
    @try { 
    [threadManagedObjectContext processPendingChanges]; 
    } 
    @catch (NSException * e) { 
    DLog(@"%@", [e description]); 
    [persistentStoreCoordinator unlock]; 
    } 
    @finally { 
    // pass 
    } 

    NSNotificationCenter *dnc = [NSNotificationCenter defaultCenter]; 
    [dnc addObserver:self selector:@selector(threadControllerContextDidSave:) name:NSManagedObjectContextDidSaveNotification object:threadManagedObjectContext]; 
    @try { 
    NSError *error; 
    if (![threadManagedObjectContext save:&error]) { 
     DLog(@"%@", [error localizedDescription]); 
     [persistentStoreCoordinator unlock]; 
     [self performSelectorOnMainThread:@selector(handleSaveError:) withObject:nil waitUntilDone:NO]; 
    } 
    } @catch (NSException *e) { 
    DLog(@"%@", [e description]); 
    [persistentStoreCoordinator unlock]; 
    } @finally { 
    // pass 
    } 
    [dnc removeObserver:self name:NSManagedObjectContextDidSaveNotification object:threadManagedObjectContext]; 

    [self performSelectorOnMainThread:@selector(parserFinished:) withObject:nil waitUntilDone:NO]; 
} 

// Merging changes causes the fetched results controller to update its results 
- (void)threadControllerContextDidSave:(NSNotification*)saveNotification { 
    // need to unlock before we let main thread merge 
    [persistentStoreCoordinator unlock]; 
    [self performSelectorOnMainThread:@selector(mergeToMainContext:) withObject:saveNotification waitUntilDone:YES]; 
} 

- (void)mergeToMainContext:(NSNotification*)saveNotification { 
    NSError *error; 
    [managedObjectContext mergeChangesFromContextDidSaveNotification:saveNotification]; 
    if (![managedObjectContext save:&error]) { 
    DLog(@"%@", [error localizedDescription]); 
    [self handleSaveError:nil]; 
    } 
} 

`

+0

Esta es una muy buena respuesta, pero tenga en cuenta este hilo también: http://stackoverflow.com/questions/3446983/collection-was-mutated-while-being-enumerated-on-executefetchrequest explica que threadManagedObjectContext DEBE crearse dentro del nuevo hilo. – gonso

+0

Swift 2+ tiene una forma mejor de administrar MOC concurrentes. Encontré este tutorial bastante útil https://www.cocoanetics.com/2012/07/multi-context-coredata/ – Neilc

1

lo siento por mi Inglés (soy francés). Tuve el mismo problema y me di cuenta de que había llamado a un método en Core Data Framework (inserción de un objeto) desde un segundo hilo. Simplemente llamo a este método desde el hilo principal usando performSelectorOnMainThread y resuelve mi problema. Espero que te ayude.

+0

Esto también resolvió mi problema:) Stéphane Garzino – Bhat

2

Gracias a todos, pude deshacerte de la molesta excepción siguiendo tus consejos.

Era el problema de enhebrado que parecía causar la excepción. En mi caso, tuve el subproceso principal que engendraba subprocesos de trabajo que captaban el XML, analizaban, creaban el objeto gestionado necesario y los guardaban.

Intenté una salida perezosa utilizando performSelectorOnMainThread para guardar pero eso no funcionó.

Mi enfoque final fue crear una clase llamada ThreadDataService con su propio ManagedObjectContext y cada thread tiene una instancia de ThreadDataService, básicamente lo que Adriaan sugirió.

Nuevamente, gracias por todas las respuestas. ¡Ustedes molan!

1

Tuve el mismo problema y al buscar una respuesta encontré esto. Mi problema fue que comencé 2 subprocesos que funcionaban en el mismo contexto administrado y se bloquean al guardarlos en la tienda persistente; si cada subproceso tiene su propio contexto, el problema no aparece. Pero podría resolverse simplemente bloqueando la tienda persistente, pero creo que los 2 contextos gestionados son la solución correcta.

Saludos

11

usted tiene que seguir la regla:

NSManagedObjectContext se debe crear en el mismo hilo que utiliza ella. (O en otras palabras, cada hilo debe tener su propia MOC)

Violación de la regla anterior causar la siguiente excepción:

  • Excepción en *** -_referenceData64 única definida para la clase abstracta. Definir - [NSTemporaryObjectID_default _referenceData64] !,

Otro problema podría alguien cara es, si se utiliza el NSFetchedResultsController, los delegados no será anunciado en las clases de interfaz de usuario.

¡Espero que esta respuesta ayude a alguien!

+0

me caí al utilizar "NSFetchedResultsController, los delegados no ser llamado en las clases de UI ". ¿Qué debería hacer? –

2

Haga su mapeo de nsmanagedobject de datos y ahorro de managedobjectcontext en el siguiente bloque, de forma que se bloquee el managedobjectcontext accedan por otro subproceso y resolvió el choque.

[context performBlockAndWait:^{ 

    //your code 
    [context save:&error]; 

}]; 
+0

NSInvalidArgumentException ', razón:' Sólo se puede usar -performBlockAndWait: en un NSManagedObjectContext que se creó con una cola –

Cuestiones relacionadas