Загадочная ошибка от Базовых Данных: NSInvalidArgumentException, причина: referenceData64 только определяется для абстрактного класса

Я делаю приложение для iPhone, которое считывает данные с XML-файла, превратите их в Базовые Управляемые объекты Данных и сохраните их.

Приложение хорошо работает, главным образом, на меньшем наборе данных/XML, который содержит ~150 объектов. Я сказал главным образом, потому что 10% времени, я получу следующее исключение из CoreData при попытке сохранить контекст:

* Завершение приложения из-за неперехваченного исключения 'NSInvalidArgumentException', причина: '* - _referenceData64 только определенный для абстрактного класса. Определите - [NSTemporaryObjectID_default _referenceData64]!'

На большем наборе данных (~2000), это происходит каждый раз, но не на том же месте. Это могло перестать работать на 137-м рекордном, 580-м, или самое последнее. Я попытался переместить точку сохранения (на объект, на 10 объектов, сохраните, как только все объекты являются alloc/init'ed), но я всегда поражал исключение выше.

Я погуглил исключение и видел, что кто-то имел те же проблемы, но не видел разрешений.

Мой следующий шаг был упрощением управляемых объектов и отношений к точке где эта ошибка остановки и сборка оттуда для изоляции проблемы. Последнее средство должно угробить Базовые Данные и просто непосредственно сохранить в sqllite.

Спасибо за всю Вашу справку!

31
задан gerry3 5 January 2010 в 23:31
поделиться

3 ответа

У меня та же проблема. Она работает для меньших наборов данных, но для больших наборов я получаю ошибки "_referenceData64 определено только для абстрактного класса". В моей модели нет абстрактных сущностей.

EDIT:

Думаю, я решил эту проблему. Проблема в моем случае заключалась в путанице с моими ре-потоками. Вот рекомендации, которым я руководствовался, чтобы исправить это:

  1. Я разбираю XML данные в потоке. При запуске этого потока создайте новый NSManagedObjectContext, используя тот же постоянный координатор хранилища, что и основной поток NSManagedObjectContext.
  2. Любые новые объекты, которые вы создаете в потоке, должны быть сделаны для NSManagedObjectContext. Если вам нужно скопировать объекты из NSManagedObjectContext главного потока, скопируйте их по ID. Т.е.
    NSManagedObjectID *objectID = [foo objectID];
    . FooClass *newFoo = [(FooClass*)[threadManagedObjectContext objectWithID:objectID] сохраняют]
  3. После завершения парсинга необходимо сохранить изменения, внесенные в NSManagedObjectContext потока. Вы должны заблокировать координатора постоянного хранилища. Я использовал следующее (неполный код):

`

 - (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];  
  }  
}  

`

30
ответ дан 27 November 2019 в 22:25
поделиться

Спасибо всем, я смог избавиться от надоедливого исключения, следуя вашим советам.

Казалось, что именно проблема с нитями стала причиной исключения. В моем случае, у меня был основной поток, порождающий рабочие потоки, которые получали XML, анализировали, создавали необходимый управляемый объект и сохраняли их.

Я попробовал ленивый выход, используя performSelectorOnMainThread для сохранения, но это не сработало.

Моим последним подходом было создание класса под названием ThreadDataService со своим собственным ManagedObjectContext, и каждый поток имеет один экземпляр ThreadDataService, в основном то, что предложил Адриаан.

Еще раз спасибо за все ответы. Ребята, зажигайте!

2
ответ дан 27 November 2019 в 22:25
поделиться

извините за мой английский (я француженка). У меня была та же проблема, и я понял, что вызвал метод на Core Data Framework (вставка объекта) из второго потока. Я просто вызвал этот метод из основного потока с помощью performSelectorOnMainThread, и он решил мою проблему. Надеюсь, он вам поможет.

1
ответ дан 27 November 2019 в 22:25
поделиться
Другие вопросы по тегам:

Похожие вопросы: