exc_bad_access для insertNewObjectForEntityForName: inManagedObjectContext - PullRequest
2 голосов
/ 19 марта 2010

Я написал минимальный пример кода проблемы, с которой я столкнулся. Я реализовал фоновую работу двумя способами: вручную порождая потоки и позволяя NSOperation обрабатывать потоки. В обоих случаях я создаю NSManagedObjectContexts для каждого потока / операции.

Когда я сам создаю темы с performSelectorInBackground:withObject:, все работает нормально. Когда я переключаюсь на передачу своих объектов на NSOperationQueue, я вижу следующие ошибки при попытке сохранить операции NSManagedObjectContext.

-EXC_BAD_ACCESS - Серьезная ошибка приложения. Исключительная ситуация при обработке изменения базовых данных: *** - [NSCFSet addObject:]: попытка вставить ноль с userInfo (ноль) - _referenceData64 определено только для абстрактного класса. Определить - [NSTevenObjectID_default _referenceData64]!

Я считаю, что ошибка, особенно с учетом последней ошибки, связана с использованием временного objectID для передачи объектов между потоками / контекстами. Возможно, что еще хуже, я как-то передаю NSManagedObjects между потоками.

В любом случае, я не могу найти код, который бы подсказывал, что я делаю это.

Мой пример минимального кода можно найти здесь .

Большая часть работы выполняется в AppDelegate в awakeFromNib. Установите EXECUTE_WITH_NSOPERATION в 0 для запуска с performSelectorInBackground:withObject:. Оставьте EXECUTE_WITH_NSOPERATION на 1 для выполнения с NSOperationQueue, который создает группу MCBoardParse объектов.

Я вижу это только под 10.6.

Оригинал

У меня есть приложение Какао, построенное на платформах 10.5. В NSOperation В цикле я быстро создаю сотни NSManagedObjects. Часто создание этих NSManagedObejcts завершается с ошибкой EXC_BAD_ACCESS. Это происходит как при управлении подсчетом ссылок, так и при сборке мусора.

    for (offsetCount; offsetCount < [parsedData count]; offsetCount++) {
  NSManagedObject *child = [NSEntityDescription insertNewObjectForEntityForName:@"Thread" inManagedObjectContext:[self moc]];
  Thumbnail *thumb = [Thumbnail insertInManagedObjectContext:[self moc]];
  Image *image = [Image insertInManagedObjectContext:[self moc]];
  ...
 }

Эскиз и изображение являются подклассами NSManagedObject, созданными с помощью mogenerator. insertInManagedObjectContext: выглядит как

    NSParameterAssert(moc_);
    return [NSEntityDescription insertNewObjectForEntityForName:@"Thumbnail" inManagedObjectContext:moc_];

    NSParameterAssert(moc_);
 return [NSEntityDescription insertNewObjectForEntityForName:@"Image" inManagedObjectContext:moc_];
The NSManagedObjectContext returned by [self moc] is created for the NSOperation with 

    NSPersistentStoreCoordinator *coord = [(MyApp_AppDelegate *)[[NSApplication sharedApplication] delegate] persistentStoreCoordinator];
 self.moc = [[NSManagedObjectContext alloc] init];
 [self.moc setPersistentStoreCoordinator:coord];
 [[NSNotificationCenter defaultCenter] addObserver:self
      selector:@selector(contextDidSave:) 
       name:NSManagedObjectContextDidSaveNotification 
     object:self.moc];
 [self.moc setMergePolicy:NSMergeByPropertyObjectTrumpMergePolicy];
 [self.moc setUndoManager:nil];
 [self.moc setRetainsRegisteredObjects:YES];

moc определяется как (nonatomic, retain) и синтезируется. Насколько я могу судить, постоянное хранилище и мой appDelegate не имеют никаких оснований и не собирают мусор.

Трассировка стека выглядит как

Thread 2 Crashed:  Dispatch queue: com.apple.root.default-priority
0   libauto.dylib                  0x00007fff82d63600 auto_zone_root_write_barrier + 688
1   libobjc.A.dylib                0x00007fff826f963b objc_assign_strongCast_gc + 59
2   com.apple.CoreFoundation       0x00007fff88677068 __CFBasicHashAddValue + 504
3   com.apple.CoreFoundation       0x00007fff88676d2f CFBasicHashAddValue + 191
4   com.apple.CoreData             0x00007fff82bdee5e -[NSManagedObjectContext(_NSInternalAdditions) _insertObjectWithGlobalID:globalID:] + 190
5   com.apple.CoreData             0x00007fff82bded24 -[NSManagedObjectContext insertObject:] + 148
6   com.apple.CoreData             0x00007fff82bbd75c -[NSManagedObject initWithEntity:insertIntoManagedObjectContext:] + 716
7   com.apple.CoreData             0x00007fff82bdf075 +[NSEntityDescription insertNewObjectForEntityForName:inManagedObjectContext:] + 101
8   com.yourcompany.MyApp         0x000000010002c7a7 +[_Thumbnail insertInManagedObjectContext:] + 256 (_Thumbnail.m:14)
9   com.yourcompany.MyApp         0x000000010002672d -[ThreadParse main] + 10345 (ThreadParse.m:174)
10  com.apple.Foundation           0x00007fff85ee807e -[__NSOperationInternal start] + 698
11  com.apple.Foundation           0x00007fff85ee7d23 ____startOperations_block_invoke_2 + 99
12  libSystem.B.dylib              0x00007fff812bece8 _dispatch_call_block_and_release + 15
13  libSystem.B.dylib              0x00007fff8129d279 _dispatch_worker_thread2 + 231
14  libSystem.B.dylib              0x00007fff8129cbb8 _pthread_wqthread + 353
15  libSystem.B.dylib              0x00007fff8129ca55 start_wqthread + 13

Мое приложение аварийно завершает работу в других местах с EXC_BAD_ACCESS, но это код, с которым это происходит чаще всего. Все трассировки стека выглядят одинаково и имеют отношение к CFHash.

1 Ответ

1 голос
/ 20 марта 2010

Если вы терпите крах с exc_bad_access, это означает, что вы перевыпускаете объект или вызываете методы для объекта после того, как он был освобожден. Обе эти ситуации плохие и не имеют ничего общего с базовыми данными. Тот факт, что вы используете сборщик мусора, вероятно, является признаком того, что что-то разыменовывается и, следовательно, собирается мусором раньше, чем вы ожидаете.

Первый вопрос, однако, вы создаете новый NSManagedObjectContext для каждого из этих экземпляров NSOperation?

Во-вторых, я бы порекомендовал включить NSZombie (что, я полагаю, вы можете теперь делать с помощью инструментов), и это поможет сузить, какой код вызывает объект после выпуска и т. Д. Выполнение поиска Google на NSZombie Инструменты найдут несколько статей с практическими рекомендациями.

обновление

Поскольку это проблема 10.6 только тогда, она может иметь отношение к экземплярам NSOperation вместо экземпляров Core Data. Ваши операции помечены как параллельные? Причина, по которой я спрашиваю, состоит в том, что NSOperation игнорирует параллельный флаг на 10.6, и это может привести к некоторым неприятным сюрпризам.

обновление 2

Просто заметка, пока я рассматриваю общую проблему. Линия:

self.moc = [[NSManagedObjectContext alloc] init];

Будет утечка памяти (по крайней мере, когда GC выключен), если у вас нет выпуска, так как alloc init будет увеличивать счет сохранения, а затем вызов [self setMoc:] также увеличивает счет хранения.

...