insertNewObjectForEntityForName:inManagedObjectContext 上的 exc_bad_access

发布于 2024-08-26 04:02:29 字数 4615 浏览 3 评论 0原文

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

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

-EXC_BAD_ACCESS - 严重的应用程序错误。核心数据更改处理期间捕获异常:*** -[NSCFSet addObject:]: attempts to insert nil 与用户信息(空) - _referenceData64 仅为抽象类定义。定义-[NSTemporaryObjectID_default _referenceData64]!

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

不管怎样,我找不到任何代码表明我正在这样做。

我的最小代码示例可以在此处找到。

大部分工作是在 awakeFromNib 中的 AppDelegate 中完成的。将 EXECUTE_WITH_NSOPERATION 设置为 0 以使用 performSelectorInBackground:withObject: 运行。将 EXECUTE_WITH_NSOPERATION 保留为 1,以使用 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 都是使用 mogenerator 生成的 NSManagedObject 的子类。 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, keep) 并被合成。据我所知,持久存储和我的 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 有关。

I wrote a minimal code example of the issue I am having. I implemented the background work two ways: manually spawning threads and letting NSOperation handle threading. In both cases I am creating NSManagedObjectContexts for each thread/operation.

When I spawn the threads myself with performSelectorInBackground:withObject: everything works fine. When I switch to passing my objects off to an NSOperationQueue I see the following errors when attempting to save the operations NSManagedObjectContext.

-EXC_BAD_ACCESS
- Serious application error. Exception was caught during Core Data change processing: *** -[NSCFSet addObject:]: attempt to insert nil
with userInfo (null)
- _referenceData64 only defined for abstract class. Define -[NSTemporaryObjectID_default _referenceData64]!

I believe the bug, especially given the last error, has to do with using a temporary objectID to pass objects between threads/contexts. Possibly, even worse, I'm somehow passing NSManagedObjects between threads.

Either way, I can't find any code which would suggest I am doing so.

My minimal code example can be found here.

Most of the work is done in the AppDelegate in awakeFromNib. Set EXECUTE_WITH_NSOPERATION to 0 to run with performSelectorInBackground:withObject:. Leave EXECUTE_WITH_NSOPERATION on 1 to execute with the NSOperationQueue which creates a bunch of MCBoardParse objects.

I'm only seeing this under 10.6.

Original

I have a Cocoa application built on 10.5 frameworks. In an NSOperation In a loop I am quickly creating hundreds of NSManagedObjects. Frequently the creation of those NSManagedObejcts will crash with a EXC_BAD_ACCESS error. This happens under both reference counted memory management and garbage collection.

    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 and Image are both subclasses of NSManagedObject generated with mogenerator. insertInManagedObjectContext: looks like

    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 is defined as (nonatomic, retain) and synthesized. As far as I can tell it, the persistent store and my appDelegate have no reason to be and are not being garbage collected.

The stack trace looks like

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

My app is crashing in other places with EXC_BAD_ACCESS but this is code that it happens most with. All of the stack traces look similar and have something to do with CFHash.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

水染的天色ゝ 2024-09-02 04:02:29

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

第一个问题是,您是否为每个 NSOperation 实例创建一个新的 NSManagedObjectContext ?

其次,我建议打开 NSZombie (我相信您现在可以通过工具来完成),这将有助于缩小发布后调用对象的代码的范围,等等。在 NSZombie 和 Instruments 将显示几篇操作方法文章。

更新

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

更新2

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

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

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

If you are crashing with a exc_bad_access that means you are over-releasing an object or you are calling methods on an object after it has been released. Both of these situations are bad and have nothing to do with Core Data. The fact that you are using garbage collection is probably a clue that something is getting dereferenced and therefore getting garbage collected before you expect it to.

First question though, are you creating a new NSManagedObjectContext for each one of these NSOperation instances?

Second, I would recommend turning on NSZombie (which I believe you can do through instruments now) and that will help narrow down what code is calling an object after release, etc. Doing a Google search on NSZombie and Instruments will turn up several how-to articles.

update

Since this is a 10.6 issue only then it may have to do with the NSOperation instances instead of the Core Data instances. Are your operations flagged as concurrent? The reason I ask is that NSOperation ignores the concurrent flag on 10.6 and that can lead to some nasty surprises.

update 2

Just a note while I am reviewing the overall problem. The line:

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

Will leak memory (at least while GC is off) if you do not have a release as the alloc init will increment the retain count and then the [self setMoc:] call also increments the retain count.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文