我写了一个关于我遇到的问题的最小代码示例。我以两种方式实现了后台工作:手动生成线程并让NSOperation
处理线程。在这两种情况下,我都为每个线程/操作创建NSManagedObjectContexts
。
当我用performSelectorInBackground:withObject:
自己生成线程时,一切正常。当我切换到将对象传递给NSOperationQueue
时,我在尝试保存操作NSManagedObjectContext
时看到以下错误。
-EXC_BAD_ACCESS - 严重的应用错误。在Core Data更改处理期间捕获到异常:*** - [NSCFSet addObject:]:尝试插入nil 用户信息(null) - 仅为抽象类定义的_referenceData64。定义 - [NSTemporaryObjectID_default _referenceData64]!
我相信这个错误,特别是考虑到最后一个错误,与使用临时objectID在线程/上下文之间传递对象有关。可能,更糟糕的是,我在某种程度上在线程之间传递NSManagedObjects
。
无论哪种方式,我找不到任何暗示我这样做的代码。
我的最小代码示例可以找到here。
大多数工作都在AppDelegate
的{{1}}内完成。将awakeFromNib
设置为0以使用EXECUTE_WITH_NSOPERATION
运行。将performSelectorInBackground:withObject:
保留为1以使用EXECUTE_WITH_NSOPERATION
执行,这会创建一堆NSOperationQueue
个对象。
我只在10.6下看到这个。
我有一个基于10.5框架构建的Cocoa应用程序。在MCBoardParse
循环中,我正在快速创建数百个NSOperation
。通常,NSManagedObjects
的创建将因EXC_BAD_ACCESS错误而崩溃。这在引用计数的内存管理和垃圾收集下都会发生。
NSManagedObejcts
缩略图和图像都是使用生成器生成的 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
看起来像
insertInManagedObjectContext:
moc定义为 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];
并合成。据我所知,持久存储和我的(nonatomic, retain)
没有理由存在并且没有被垃圾收集。
堆栈跟踪看起来像
appDelegate
我的应用程序在EXC_BAD_ACCESS的其他地方崩溃,但这是它最常发生的代码。所有堆栈跟踪看起来都很相似,与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
有关。
答案 0 :(得分:1)
如果您使用exc_bad_access崩溃,则意味着您过度释放对象,或者在对象释放后调用对象上的方法。这两种情况都很糟糕,与Core Data无关。你正在使用垃圾收集的事实可能是一个线索,有些东西被取消引用,因此在你预期之前收集垃圾。
第一个问题,您是否为这些NSOperation实例中的每一个创建了一个新的NSManagedObjectContext
?
其次,我建议启用NSZombie
(我相信你现在可以通过乐器进行操作),这将有助于缩小发布后调用对象的代码等等。在{{进行Google搜索1}}和仪器将会出现几篇how-to文章。
由于这只是10.6问题,因此它可能与NSOperation实例而不是Core Data实例有关。您的操作是否标记为并发?我问的原因是NSOperation忽略了10.6上的并发标志,这可能会导致一些令人讨厌的意外。
在审核整体问题时,请注意。这一行:
NSZombie
如果您没有释放,将泄漏内存(至少在GC关闭时),因为alloc init将增加保留计数,然后[self setMoc:]调用也会增加保留计数。