2010-01-05 6 views
28

Ich mache eine iPhone App, die Daten aus einer XML-Datei liest, sie in Core Data Managed Objects wandelt und sie speichert.Kryptischer Fehler von Core Data: NSInvalidArgumentException, Grund: referenceData64 nur für abstrakte Klasse definiert

Die Anwendung funktioniert gut, meist auf kleineren Datensatz/XML, die ~ 150 Objekte enthält. Ich sagte, vor allem, weil 10% der Zeit, würde ich die folgende Ausnahme von Coredata erhalte beim Versuch, den Kontext zu speichern:

* App beenden aufgrund nicht abgefangene Ausnahme ‚NSInvalidArgumentException‘, Grund: ‚* -_referenceData64 nur definiert für abstrakte Klasse. Definieren Sie - [NSTemporaryObjectID_default _referenceData64]! '

Bei einem größeren Datensatz (~ 2000) passiert dies jedes Mal, aber nicht am selben Ort. Es könnte auf dem 137. Rekord, 580 oder dem allerletzten scheitern. Ich habe versucht, den Speicherpunkt zu verschieben (pro Objekt, pro 10 Objekte, speichern, sobald alle Objekte zugewiesen/init sind), aber ich habe immer die Ausnahme oben getroffen.

Ich habe die Ausnahme gegoogelt und sah jemanden mit den gleichen Problemen, aber keine Auflösungen gesehen.

Mein nächster Schritt war, die verwalteten Objekte und Beziehungen zu einem Punkt zu vereinfachen, an dem dieser Fehler aufhört, und von dort zu bauen, um das Problem zu isolieren. Der letzte Ausweg besteht darin, Core Data abzuzweigen und direkt in sqllite zu speichern.

Vielen Dank für Ihre Hilfe!

+0

Verwenden Sie abstrakte Entitäten im Modell? –

+0

Hallo Marcus, ich habe keine abstrakte Entitäten verwendet, aber ich habe mehrere Threads verwendet und ich habe nicht die Regeln um Kerndaten in Threads zu verstehen. – Brombie

+0

Ich bin mir nicht ganz sicher, aber es scheint mir, dass Sie eine abstrakte Entität haben, die Sie instanziieren möchten. Kannst du uns über das Erbe aufklären? Was für eine seltsame Fehlermeldung! – beinstein

Antwort

27

Ich habe das gleiche Problem. Es funktioniert für kleinere Datensätze, aber für größere Mengen bekomme ich "_referenceData64 nur für abstrakte Klasse" -Fehler definiert. In meinem Modell gibt es keine abstrakten Entitäten.

EDIT:

Ich denke, ich habe das gelöst. Das Problem in meinem Fall war eine Verwirrung meinerseits Re Threads. Hier sind die Richtlinien, die ich befolgt habe, um es zu beheben:

  1. Ich parse XML-Daten in einem Thread. Erstellen Sie nach dem Start dieses Threads einen neuen NSManagedObjectContext mit dem gleichen permanenten Speicherkoordinator wie NSManagedObjectContext Ihres Hauptthreads.
  2. Alle neuen Objekte, die Sie in Ihrem Thread erstellen, sollten für den NSManagedObjectContext des Threads erstellt werden. Wenn Sie Objekte aus NShandagedObjectContext des Hauptthreads kopieren müssen, kopieren Sie sie nach ID. I.e.
    NSManagedObjectID *objectID = [foo objectID];
    FooClass *newFoo = [(FooClass*)[threadManagedObjectContext objectWithID:objectID] retain]
  3. Nach Abschluss der Analyse müssen Sie die am NSManagedObjectContext des Threads vorgenommenen Änderungen speichern. Sie müssen den Persistent Store Coordinator sperren. Früher habe ich den folgenden (unvollständigen Code):

`

- (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

Dies ist eine sehr gute Antwort, aber bitte beachten Sie auch diesen Thread: http://stackoverflow.com/questions/3446983/collection-was-mutated-while-being-enumerated-on-executefetchrequest es erklärt, dass der threadManagedObjectContext muss erstellt werden innerhalb des neuen Threads. – gonso

+0

Swift 2+ bietet eine bessere Möglichkeit zur Verwaltung gleichzeitiger MOCs. Ich dieses tutorial sehr nützlich https://www.cocoanetics.com/2012/07/multi-context-coredata/ – Neilc

1

sorry für mein Englisch (ich bin französisch). Ich hatte das gleiche Problem und ich erkannte, dass ich eine Methode auf Core Data Framework (Einfügen eines Objekts) aus einem zweiten Thread aufgerufen. Ich rufe diese Methode einfach aus dem Haupt-Thread mit performSelectorOnMainThread und es löst mein Problem. Ich hoffe, es wird dir helfen.

+0

Das ist mein Problem zu lösen:) Stéphane Garzino – Bhat

2

Danke allen, ich konnte die lästige Ausnahme loswerden, indem ich Ihren Tipps folgte.

Es war das Threading-Problem, das die Ausnahme zu verursachen schien. In meinem Fall hatte der Hauptthread Worker-Threads, die XML abrufen, analysieren, das erforderliche verwaltete Objekt erstellen und speichern.

Ich versuchte einen faulen Ausweg mit performSelectorOnMainThread zum Speichern, aber das hat nicht funktioniert.

Mein letzter Ansatz bestand darin, eine Klasse namens ThreadDataService mit ihrem eigenen ManagedObjectContext zu erstellen, und jeder Thread hat eine Instanz von ThreadDataService, was Adriaan vorgeschlagen hatte.

Nochmals vielen Dank für alle Antworten. Ihr Jungs rockt!

1

Ich hatte das gleiche Problem und auf der Suche nach einer Antwort habe ich das gefunden. Mein Problem war, dass ich 2 Threads gestartet habe, die am selben verwalteten Kontext gearbeitet haben, der beim Speichern im persistenten Speicher abgestürzt ist - wenn jeder Thread seinen eigenen Kontext hat, tritt das Problem nicht auf. Aber es wurde möglicherweise durch das Sperren des persistenten Speichers gelöst, aber ich glaube, dass die 2 verwalteten Kontexte die richtige Lösung sind.

Grüße

11

Sie haben die Regel folgen:

NSManagedObjectContext auf dem gleichen Thread erstellt werden müssen, die es verwendet. (Oder mit anderen Worten muss jeder Thread seine eigene MOC)

Verletzung der obigen Regel führt die folgende Ausnahme:

  • Ausnahme in *** -_referenceData64 nur für abstrakte Klasse definiert. Definieren - [NSTemporaryObjectID_default _referenceData64] !,

Ein weiteres Problem könnte jemand konfrontiert wird, wenn die NSFetchedResultsController verwenden, werden die Delegierten nicht auf den UI-Klassen aufgerufen werden.

Ich hoffe, diese Antwort wird jemandem helfen!

+0

ich diesen Absturz bekam während „NSFetchedResultsController verwenden, werden die Delegierten nicht in den UI-Klassen aufgerufen werden. "Was soll ich tun? –

2

Machen Sie Ihr Mapping von nsmanagedobject Daten und Speichern von managedobjectcontext im folgenden Block, so dass es den Zugriff auf managedobjectcontext von einem anderen Thread sperrt und den Absturz gelöst.

[context performBlockAndWait:^{ 

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

}]; 
+0

NSInvalidArgumentException ‚Grund:‘ Kann nur verwenden -performBlockAndWait: auf einem NSManagedObjectContext, die mit einer Warteschlange erstellt wurde –

Verwandte Themen