我无法使用非主 MOC 在后台线程上创建 NSManagedObject 的新实例

Posted

技术标签:

【中文标题】我无法使用非主 MOC 在后台线程上创建 NSManagedObject 的新实例【英文标题】:I can't make a new instance of NSManagedObject on background thread with non-main MOC 【发布时间】:2012-05-17 16:27:00 【问题描述】:

我在后台线程上研究了大量关于 Core Data 的帖子,我觉得我(在纸面上)了解需要做什么。我想我们会看到的。我正在将现有的 OS X 应用程序迁移到 Core Data,并且在异步线程上创建 NSManagedObject 的新实例时遇到问题。

这是我在进入后台线程后立即运行的代码示例:

NSLog(@"JSON 1");
NSManagedObjectContext * context = [[NSManagedObjectContext alloc] init];
[context setPersistentStoreCoordinator:[[NSApp delegate] persistentStoreCoordinator]];
asset = (MTAssetInfo*)[NSEntityDescription insertNewObjectForEntityForName:@"Info" inManagedObjectContext:context];
NSLog(@"JSON 2");

结果是第一条日志消息(@"JSON 1") 被调用了31 次,而第二条日志消息(@"JSON 2") 从未被调用。对象未正确生成和返回。

这个Info 实体的模型非常复杂,有一些可转换的属性可能设置正确也可能不正确。奇怪的是,类似的代码在主线程上运行,而主 MOC 运行良好。没有问题。

编辑 - 更多上下文

异步调用来自这里:

for (NSNumber *sectionID in sectionsToShow) 
    dispatch_group_async(group, queue, ^
        MTAssetInfo *asset = [self assetWithRefID:[sectionID unsignedIntegerValue]];
        if (asset != nil) 
            [sectionsLock lock];
            [sectionsTemp addObject:asset];
            [sectionsLock unlock];
        
    );

assetWithRefID 方法永远不会返回一个对象,因为其他代码 sn-p。它永远不会成功地将 NSManagedObject 从后台线程的上下文中拉出。

【问题讨论】:

您能解释一下的结果是第一个日志消息被调用了31次,而第二个日志消息从未被调用过。?然后,如果可能,提供其他代码。没有细节很难发生什么。谢谢。 请添加调用此线程的示例。细节是获得帮助的关键。 我指的是我包含的代码中的两条 NSLog 消息。从字面上看,控制永远不会超出我应该取回对象的界限。 JSON 2 NSLog 消息永远不会被执行。 我感觉这可能是由于实体模型属性(NSDictionaries、NSArrays、自定义对象等)的复杂性。但它在主 MOC 的主线程上工作正常,只是在后台线程上不行。 我刚刚对一个只有一个属性的测试实体进行了基本测试,仍然没有骰子。 【参考方案1】:

您必须提供更多信息才能获得真正的帮助,但我敢打赌,您的问题是 NSManagedDocument 后台线程中发生的错误。

我会为所有消息(名称:nil 对象:nil)注册一个 NSNotificationCenter,然后将它们打印出来。我敢打赌,您会在其中看到失败的状态更改或错误消息。

您可能想在它周围尝试一个 @try/@catch 块,以查看是否抛出了异常。

也许它会给你更多的继续。

另外一个建议... Swizzling 不一定是生产产品的正确工具,但它在调试方面几乎是无与伦比的。我已经对几个完整的类进行了方法转换,以便在每次调用之前/之后发送详细的 NSNotification。

它为我节省了大量时间,并帮助我找到了一些邪恶的错误。现在,当 CoreData 中发生某些事情时,我取出我的一组类,将它们链接起来,然后查看我想要的所有细节。

我知道这并不能完全回答你的问题,但希望它能让你走上正轨,这样你就可以提供更多信息并解决所有问题。

如果这对你来说太多了,创建一个子类并实例化它,使用类似的方法调用 super.您可以很容易地了解整个流程。

【讨论】:

以上是关于我无法使用非主 MOC 在后台线程上创建 NSManagedObject 的新实例的主要内容,如果未能解决你的问题,请参考以下文章

在后台线程中更新托管对象上下文

CoreData prepareForDeletion 调用无限次

如何通知主 MOC,后台 MOC 的变化

在私有/后台队列上创建 NSManagedObjectContext:怎么办?

UndoManager 和多个 MOC

在非主线程里面使用NSTimer创建和取消定时任务