Cryptic error from Core Data: NSInvalidArgumentException, reason: referenceData64 only defined for abstract class
I have the same issue. It works for smaller data sets, but for larger sets I get "_referenceData64 only defined for abstract class" errors. There's no abstract entities in my model.
EDIT:
I think I got this resolved. The issue in my case was a confusion on my part re threads. Here's the guidelines I followed to fix it:
- I parse XML data in a thread. On launching said thread, create a new NSManagedObjectContext using the same persistent store coordinator as your main thread's NSManagedObjectContext.
- Any new objects you make in your thread should be made for the thread's NSManagedObjectContext. If you have to copy over objects from the main thread's NSManagedObjectContext, copy over by ID. I.e.
NSManagedObjectID *objectID = [foo objectID];
FooClass *newFoo = [(FooClass*)[threadManagedObjectContext objectWithID:objectID] retain] - When finished parsing, you need to save the changes made to the thread's NSManagedObjectContext. You must lock the persistent store coordinator. I used the following (incomplete 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];
}
}
`
You have to follow the rule:
NSManagedObjectContext must be created on the same thread which uses it. (OR in other words, every Thread must have its own MOC)
Violation of above rule cause the following exception:
- Exception in *** -_referenceData64 only defined for abstract class. Define -[NSTemporaryObjectID_default _referenceData64]!,
Another problem somebody might face is, if using the NSFetchedResultsController
, the delegates will not be called on the UI classes.
I hope this answer will help someone!
Do your mapping of nsmanagedobject
data and saving of managedobjectcontext
in the following block so it locks the managedobjectcontext
from accessing by another thread and resolved the crash.
[context performBlockAndWait:^{
//your code
[context save:&error];
}];