Cryptic error из Core Data: NSInvalidArgumentException, причина: referenceData64 определен только для абстрактного класса
Я делаю приложение iPhone, которое считывает данные из XML файла, превращает их в управляемые объекты Core Data и сохраняет их.
Приложение работает отлично, в основном, на меньшем наборе данных /XML, который содержит ~ 150 объектов. Я сказал в основном, что в 10% случаев я получаю следующее исключение от CoreData при попытке сохранить контекст:
* Завершение приложения из-за неперехваченного исключения "NSInvalidArgumentException", причина: '* -_referenceData64, определенная только для абстрактного класса. Определить - [NSTemporaryObjectID_default _referenceData64]!
В большем наборе данных (~ 2000) это происходит каждый раз, но не на том же месте. Это может потерпеть неудачу на 137-м альбоме, 580-м или самом последнем. Я попытался переместить точку сохранения (за объект, на 10 объектов, сохранить, как только все объекты будут выделены /init 'ed), но я всегда ударил исключение выше.
Я искал исключение и увидел, что кто-то имеет те же проблемы, но не видит никаких разрешений.
Мой следующий шаг должен был упростить управляемые объекты и отношения до точки, где эта ошибка останавливается и строится оттуда, чтобы изолировать проблему. Последнее средство - вырезать Core Data и просто хранить в sqllite.
Спасибо за вашу помощь!
Ответы
Ответ 1
У меня такая же проблема. Он работает для небольших наборов данных, но для больших наборов я получаю ошибки "_referenceData64, определенные только для абстрактного класса". В моей модели нет абстрактных объектов.
EDIT:
Думаю, я решил это. Проблема в моем случае была путаницей с моей стороны. Вот рекомендации, которые я выполнил, чтобы исправить это:
- Я анализирую XML-данные в потоке. При запуске этого потока создайте новый NSManagedObjectContext, используя тот же постоянный координатор хранилища, что и ваш основной поток NSManagedObjectContext.
- Любые новые объекты, которые вы делаете в своем потоке, должны быть сделаны для потока NSManagedObjectContext. Если вам нужно скопировать объекты из основного потока NSManagedObjectContext, скопируйте его по идентификатору. Т.е.
NSManagedObjectID *objectID = [foo objectID];
FooClass *newFoo = [(FooClass*)[threadManagedObjectContext objectWithID:objectID] retain]
- Когда закончите синтаксический анализ, вам нужно сохранить изменения, внесенные в поток NSManagedObjectContext. Вы должны заблокировать постоянный координатор магазина. Я использовал следующий (неполный код):
`
- (void)onFinishParsing {
// lock the store we share with main thread 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];
}
}
`
Ответ 2
Вы должны следовать правилу:
NSManagedObjectContext должен быть создан в том же потоке, который использует Это. (ИЛИ, другими словами, каждый поток должен иметь свой собственный MOC)
Нарушение вышеприведенного правила вызывает следующее исключение:
- Исключение в *** -_referenceData64 определено только для абстрактного класса. Определить - [NSTemporaryObjectID_default _referenceData64]!,
Другая проблема, с которой может столкнуться человек, заключается в том, что при использовании NSFetchedResultsController
делегаты не будут вызываться в классах пользовательского интерфейса.
Я надеюсь, что этот ответ поможет кому-то!
Ответ 3
Сделайте свое отображение данных nsmanagedobject
и сохраните managedobjectcontext
в следующем блоке, чтобы он блокировал доступ managedobjectcontext
к другому потоку и разрешил сбой.
[context performBlockAndWait:^{
//your code
[context save:&error];
}];
Ответ 4
Извините за мой английский (я французский).
У меня была такая же проблема, и я понял, что я вызвал метод в Core Data Framework (вставка объекта) из второго потока. Я просто вызываю этот метод из основного потока, используя функцию performSelectorOnMainThread, и это разрешает мою проблему.
Надеюсь, это поможет вам.
Ответ 5
Спасибо всем, я смог избавиться от этого отвратительного исключения, следуя советам.
Это была проблема с потоками, которая, по-видимому, вызывала исключение. В моем случае у меня был основной поток, создающий рабочие потоки, которые извлекают XML, анализируют, создают необходимый управляемый объект и сохраняют их.
Я попробовал ленивый выход, используя функцию performSelectorOnMainThread для сохранения, но это не сработало.
Мой последний подход заключался в создании класса ThreadDataService с его собственным ManagedObjectContext, и каждый поток имеет один экземпляр ThreadDataService, в основном то, что предложил Адриаан.
Опять же, спасибо за все ответы. Вы, ребята, рок!
Ответ 6
У меня была такая же проблема, и при поиске ответа я нашел это. Моя проблема состояла в том, что я запустил 2 потока, которые работали в одном управляемом контексте, разбился при сохранении в постоянном хранилище, если в каждом потоке есть собственный контекст, проблема не возникает. Но это могло быть разрешено путем блокировки постоянного хранилища, но я считаю, что 2 управляемых контекста - правильное решение.
Привет