2010-01-05 17 views
28

Sto facendo un'app per iPhone che legge i dati dal file XML, li trasforma in oggetti gestiti da Core Data e li salva.Errore criptico dai dati principali: NSInvalidArgumentException, motivo: referenceData64 definito solo per la classe astratta

L'applicazione funziona bene, principalmente, su set di dati più piccoli/XML che contiene ~ 150 oggetti. Ho detto soprattutto perché il 10% del tempo, mi piacerebbe avere la seguente eccezione da CoreData durante il tentativo di salvare il contesto:

* Chiusura di applicazione a causa di eccezione non identificata 'NSInvalidArgumentException', la ragione: '* -_referenceData64 solo definito per classe astratta. Definisci - [NSTemporaryObjectID_default _referenceData64]! '

Su un set di dati più grande (~ 2000), ciò accade ogni volta, ma non nello stesso punto. Potrebbe fallire nel 137 ° record, 580 ° o ultimo. Ho provato a spostare il punto di salvataggio (per oggetto, per 10 oggetti, salvare una volta che tutti gli oggetti sono alloc/init) ma ho sempre colpito l'eccezione sopra.

Ho cercato su google l'eccezione e ho visto qualcuno che ha gli stessi problemi ma non ha visto alcuna risoluzione.

Il mio prossimo passo sarebbe semplificare gli oggetti gestiti e le relazioni fino al punto in cui questo errore si interrompe e si costruisca da lì per isolare il problema. L'ultima risorsa è quella di abbandonare Core Data e archiviare direttamente in SQLite.

Grazie per tutto il vostro aiuto!

+0

Si sta utilizzando qualsiasi entità astratta nel modello? –

+0

Ciao Marcus, non ho usato entità astratte ma stavo usando più thread e non mi ero reso conto delle regole sull'uso dei Core Data nei thread. – Brombie

+0

Non ne sono del tutto sicuro, ma mi sembra che tu abbia un'entità astratta che stai cercando di istanziare. Puoi illuminarci sull'eredità? Che strano messaggio di errore! – beinstein

risposta

27

Ho lo stesso problema. Funziona con insiemi di dati più piccoli, ma per i set più grandi ottengo errori "_referenceData64 solo definiti per classi astratte". Non ci sono entità astratte nel mio modello.

EDIT:

Penso che ho avuto questo risolto. Il problema nel mio caso era una confusione da parte mia re discussioni. Ecco le linee guida che ho seguito per risolverlo:

  1. Analizzo i dati XML in una discussione. All'avvio di detto thread, creare un nuovo NSManagedObjectContext utilizzando lo stesso coordinatore di archivio permanente del NSManagedObjectContext del thread principale.
  2. Qualsiasi nuovo oggetto creato nel thread deve essere creato per NSManagedObjectContext del thread. Se devi copiare su oggetti dal NSManagedObjectContext del thread principale, copia per ID. Cioè
    NSManagedObjectID *objectID = [foo objectID];
    FooClass *newFoo = [(FooClass*)[threadManagedObjectContext objectWithID:objectID] retain]
  3. Al termine dell'analisi, è necessario salvare le modifiche apportate a NSManagedObjectContext del thread. Devi bloccare il coordinatore del negozio persistente. Ho usato il seguente (codice 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

Questa è un'ottima risposta, ma ti preghiamo di notare anche questo thread: http://stackoverflow.com/questions/3446983/collection-was-mutated-while-being-enumerated-on-executefetchrequest spiega che il threadManagedObjectContext DEVE essere creato all'interno del nuovo thread. – gonso

+0

Swift 2+ ha un modo migliore di gestire i MOC concorrenti. Ho trovato abbastanza utile questo tutorial https://www.cocoanetics.com/2012/07/multi-context-coredata/ – Neilc

1

dispiace per il mio inglese (sto francese). Ho avuto lo stesso problema e mi sono reso conto che ho chiamato un metodo su Core Data Framework (inserendo un oggetto) da un secondo thread. Ho appena chiamato questo metodo dal thread principale utilizzando performSelectorOnMainThread e risolve il mio problema. Spero che ti possa aiutare.

+0

Questo ha risolto anche il mio problema:) Stéphane Garzino – Bhat

2

Grazie a tutti, sono riuscito a sbarazzarmi dell'eccezionale eccezione seguendo i vostri suggerimenti.

Era il problema di threading che sembrava causare l'eccezione. Nel mio caso, ho avuto il thread principale che genera thread di lavoro che prelevano l'XML, analizzano, creano l'oggetto gestito necessario e li salvano.

Ho provato una via di uscita pigra utilizzando performSelectorOnMainThread per il salvataggio ma non ha funzionato.

Il mio ultimo approccio è stato quello di creare una classe chiamata ThreadDataService con il proprio ManagedObjectContext e ogni thread ha un'istanza di ThreadDataService, in pratica ciò che Adriaan aveva suggerito.

Ancora una volta, grazie per tutte le risposte. Ragazzi, rock!

1

Ho avuto lo stesso problema e durante la ricerca di una risposta ho trovato questo. Il mio problema era che ho iniziato 2 thread che hanno funzionato sullo stesso contesto gestito si è bloccato durante il salvataggio nell'archivio persistente, se ogni thread ha il proprio contesto il problema non si pone. Ma potrebbe essere stato risolto semplicemente bloccando lo store persistente, ma credo che i 2 contesti gestiti siano la soluzione giusta.

saluti

11

si deve seguire la regola:

NSManagedObjectContext deve essere creata sullo stesso thread che utilizza esso. (O in altre parole, ogni filo deve avere un suo MOC)

violazione della regola precedente causare la seguente eccezione:

  • eccezioni in *** -_referenceData64 definiti esclusivamente per classe astratta. Definire - [NSTemporaryObjectID_default _referenceData64] !,

Un altro problema che qualcuno potreste affrontare è, se si utilizza il NSFetchedResultsController, i delegati non saranno chiamati alle classi di interfaccia utente.

Spero che questa risposta aiuti qualcuno!

+0

ho avuto questo crash durante l'utilizzo di "NSFetchedResultsController, i delegati non essere chiamato sulle classi UI. ".. Cosa dovrei fare? –

2

Effettua la mappatura dei dati nsmanagedobject e il salvataggio di managedobjectcontext nel seguente blocco in modo da bloccare managedobjectcontext dall'accesso da un altro thread e risolto l'arresto anomalo.

[context performBlockAndWait:^{ 

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

}]; 
+0

NSInvalidArgumentException ', motivo:' Can only use -performBlockAndWait: su un NSManagedObjectContext che è stato creato con una coda –

Problemi correlati