2

我写了一个我遇到的问题的最小代码示例。我以两种方式实现后台工作:手动生成线程和让NSOperation处理线程。在这两种情况下,我都在NSManagedObjectContexts为每个线程/操作创建。

当我自己生成线程时,performSelectorInBackground:withObject:一切正常。当我切换到将我的对象传递给 an时,NSOperationQueue我在尝试保存操作时看到以下错误NSManagedObjectContext

-EXC_BAD_ACCESS - 严重的应用程序错误。在核心数据更改处理期间捕获到异常:*** -[NSCFSet addObject:]:尝试使用 userInfo (null) 插入 nil - _referenceData64 仅为抽象类定义。定义 -[NSTemporaryObjectID_default _referenceData64]!

我相信这个错误,特别是考虑到最后一个错误,与使用临时 objectID 在线程/上下文之间传递对象有关。可能,更糟糕的是,我不知何故NSManagedObjects在线程之间传递。

无论哪种方式,我都找不到任何建议我这样做的代码。

我的最小代码示例可以在这里找到。

大部分工作都是在 in 中完成AppDelegateawakeFromNib。设置EXECUTE_WITH_NSOPERATION为 0 以运行performSelectorInBackground:withObject:. 保留EXECUTE_WITH_NSOPERATION1 以执行NSOperationQueue创建一堆MCBoardParse对象。

我只在 10.6 下看到这个。

原来的

我有一个基于 10.5 框架的 Cocoa 应用程序。在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]];
  ...
 }

Thumbnail 和 Image 都是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.

4

1 回答 1

1

如果您因 exc_bad_access 而崩溃,这意味着您过度释放了一个对象,或者您在释放对象后调用了该对象的方法。这两种情况都很糟糕,与 Core Data 无关。您正在使用垃圾收集的事实可能是一个线索,表明某些东西正在被取消引用,因此在您期望它之前收集了垃圾。

不过,第一个问题是,您是否NSManagedObjectContext为这些 NSOperation 实例中的每一个创建了一个新实例?

其次,我建议打开NSZombie(我相信您现在可以通过工具来做到这一点),这将有助于缩小发布后调用对象的代码等范围。在 Google 上搜索NSZombie和 Instruments 会出现几篇操作指南文章.

更新

由于这只是一个 10.6 问题,因此它可能与 NSOperation 实例而不是 Core Data 实例有关。您的操作是否标记为并发?我问的原因是 NSOperation 忽略了 10.6 上的并发标志,这可能会导致一些令人讨厌的意外。

更新 2

在我审查整体问题时,请注意。该行:

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

如果您没有释放,则会泄漏内存(至少在 GC 关闭时),因为 alloc init 将增加保留计数,然后 [self setMoc:] 调用也会增加保留计数。

于 2010-03-20T17:05:46.960 回答