NSOperation 和 ARC 中 NSManagedObjectContext 保存方法上的 EXC_BAD_ACCESS,为啥?

Posted

技术标签:

【中文标题】NSOperation 和 ARC 中 NSManagedObjectContext 保存方法上的 EXC_BAD_ACCESS,为啥?【英文标题】:EXC_BAD_ACCESS on NSManagedObjectContext save method inside NSOperation and ARC, why?NSOperation 和 ARC 中 NSManagedObjectContext 保存方法上的 EXC_BAD_ACCESS,为什么? 【发布时间】:2012-02-23 18:33:09 【问题描述】:

在打开 ARC 的情况下将 NSManagedObjectContext 保存在 NSOperation 中时,我发现了一些问题。没有ARC之前一切都很好。保存期间总是给出 EXC_BAD_ACCESS。代码如下所示:

//on the main thread
-(void)someFunc

    array = ... //fetching an array of entities from a core data
    for(SomeEntity * obj in array)
    
         NSSomeOperation * op = [[NSSomeOperation alloc] initWithValue:[obj someField]];
         //start an operation
    


//NSSomeOperation implementation
//...
- (void)main 
    //some code
    NSError * error = nil;
    [mainContext lock];
    if (![mainContext save:&error])     //<--- HERE EXC_BAD_ACCESS
       //process error
          
    [mainContext unlock];
    //some code

//...

使用 [mainContext setRetainsRegisteredObjects:YES] 和 objectWithID 不能解决此问题。

EXC_BAD_ACCESS(代码=1) EXC_BAD_ACCESS(代码=13)

-[__NSCFType contextDidSave:]: unrecognized selector sent to instance 0x7fc5c505d940

An observer of NSManagedObjectContextDidSaveNotification illegally threw an exception.

Objects saved = 
    inserted = "(\n)";
    updated = "(\n    <SomeEntity: 0x7fc5c55b6220> (entity: SomeEntity; id: 0x7fc5c5052b20 ... )";  
and exception = -[__NSCFType contextDidSave:]: unrecognized selector sent to instance 0x7fc5c505d940 with userInfo = (null)

我使用单独的托管对象上下文并在此 NSOperation 中获取我的托管对象。

也许这与 Core Data 错误或 ARC 相关?也许ARC清理了一些必须保存的对象? 因为,没有 ARC,一切都很好,一切正常。当我打开 ARC - EXC_BAD_ACCESS。

有人知道为什么会这样吗?

【问题讨论】:

不,吉姆。这是在 NSOperation 内部,在另一个线程上。 好吧,我问的原因是因为你可以添加一个 NSOperation 到主队列(使用 NSOperationQueue mainQueue] addOperation:...]。如果这是在辅助线程或队列上,你在关注吗? Apple 文档使用单独的托管对象上下文,并将您的更改合并回主队列中的上下文? NSOperationQueue 在主线程上,是的。是的,我在 NSOperation 中创建了第二个 NSManagedObjectContext,但是在 init 方法中。并将更改与主 NSManagedObjectContext(在主线程上创建)上的 performSelectorOnMainThread:@selector(mergeChangesFromContextDidSaveNotification:) 合并。也许我需要在 NSOperation 的“main”方法中创建 NSManagedObjectContext 对象(第二个)? 看起来一切都是对的,如果它在主线程上的话。如果您已经在主线程上,则不需要 performSelectorOnMainThread,但这无关紧要。此外,如果它在主线程上,则使用 init 或 main 也没关系。 (对于必须在辅助线程上的工作,您应该使用 start 方法,但这与您描述的情况无关。) 如果您可以发布您的项目,我会看看它,看看我是否可以提出任何建议。 【参考方案1】:

也许 ARC 释放了一些接收 NSManagedObjectContextDidSaveNotification 的对象,这会导致异常? 我有类似的东西,并通过确保在对象被释放之前 removeObserver: 来修复它。

请注意,CoreData 异常实际上隐藏了通知中心异常,因此您看不到它。

【讨论】:

谢谢Yonat!是的,你完全正确。我刚刚尝试删除Observer: - 它没有帮助。 我在共享上下文的单身人士的dealloc 中调用了removeObserver:。删除dealloc 解决了问题,但我应该去哪里removeObserver 同时检查你是否多次调用 addObserver。经验法则是在 viewDidLoad 上执行,然后在 dealloc 上调用 removeObserver。

以上是关于NSOperation 和 ARC 中 NSManagedObjectContext 保存方法上的 EXC_BAD_ACCESS,为啥?的主要内容,如果未能解决你的问题,请参考以下文章

iOS多线程---NSOperation介绍和使用

ios多线程 -- NSOperation 简介

多线程-NSOperation

iOS开发多线程篇 09 —NSOperation简单介绍

GCD和NSOperation 的概念,用法及之间的区别

多线程 NSOperation