Я делаю приложение для iPhone, которое считывает данные с XML-файла, превратите их в Базовые Управляемые объекты Данных и сохраните их.
Приложение хорошо работает, главным образом, на меньшем наборе данных/XML, который содержит ~150 объектов. Я сказал главным образом, потому что 10% времени, я получу следующее исключение из CoreData при попытке сохранить контекст:
* Завершение приложения из-за неперехваченного исключения 'NSInvalidArgumentException', причина: '* - _referenceData64 только определенный для абстрактного класса. Определите - [NSTemporaryObjectID_default _referenceData64]!'
На большем наборе данных (~2000), это происходит каждый раз, но не на том же месте. Это могло перестать работать на 137-м рекордном, 580-м, или самое последнее. Я попытался переместить точку сохранения (на объект, на 10 объектов, сохраните, как только все объекты являются alloc/init'ed), но я всегда поражал исключение выше.
Я погуглил исключение и видел, что кто-то имел те же проблемы, но не видел разрешений.
Мой следующий шаг был упрощением управляемых объектов и отношений к точке где эта ошибка остановки и сборка оттуда для изоляции проблемы. Последнее средство должно угробить Базовые Данные и просто непосредственно сохранить в sqllite.
Спасибо за всю Вашу справку!
У меня та же проблема. Она работает для меньших наборов данных, но для больших наборов я получаю ошибки "_referenceData64 определено только для абстрактного класса". В моей модели нет абстрактных сущностей.
EDIT:
Думаю, я решил эту проблему. Проблема в моем случае заключалась в путанице с моими ре-потоками. Вот рекомендации, которым я руководствовался, чтобы исправить это:
NSManagedObjectID *objectID = [foo objectID];
.
FooClass *newFoo = [(FooClass*)[threadManagedObjectContext objectWithID:objectID] сохраняют]
`
- (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];
}
}
`
Спасибо всем, я смог избавиться от надоедливого исключения, следуя вашим советам.
Казалось, что именно проблема с нитями стала причиной исключения. В моем случае, у меня был основной поток, порождающий рабочие потоки, которые получали XML, анализировали, создавали необходимый управляемый объект и сохраняли их.
Я попробовал ленивый выход, используя performSelectorOnMainThread для сохранения, но это не сработало.
Моим последним подходом было создание класса под названием ThreadDataService со своим собственным ManagedObjectContext, и каждый поток имеет один экземпляр ThreadDataService, в основном то, что предложил Адриаан.
Еще раз спасибо за все ответы. Ребята, зажигайте!
извините за мой английский (я француженка). У меня была та же проблема, и я понял, что вызвал метод на Core Data Framework (вставка объекта) из второго потока. Я просто вызвал этот метод из основного потока с помощью performSelectorOnMainThread, и он решил мою проблему. Надеюсь, он вам поможет.