【发布时间】:2015-12-29 12:39:55
【问题描述】:
更新:我已经准备了没有神奇记录的重现问题的示例。请使用以下 URL 下载测试项目: https://www.dsr-company.com/fm.php?Download=1&FileToDL=DeadLockTest_CoreDataWithoutMR.zip
提供的项目有以下问题:获取时出现死锁 在从主线程调用的 performBlockAndWait 中。
如果使用 XCode 版本 > 6.4 编译代码,则会重现该问题。 如果使用 xCode == 6.4 编译代码,则不会重现该问题。
老问题是:
我正在致力于 IOS 移动应用程序的支持。 在最近将 Xcode IDE 从 6.4 版更新到 7.0 版(支持 IOS 9)之后,我遇到了关键问题 - 应用程序挂起。 与 xCode 6.4 相同的应用程序构建(从相同的来源生成)可以正常工作。 因此,如果应用程序是使用 xCode > 6.4 构建的 - 应用程序在某些情况下会挂起。 如果应用程序是使用 xCode 6.4 构建的 - 应用程序工作正常。
我花了一些时间来研究这个问题,结果我准备了一个测试应用程序,它有类似的案例,就像我的应用程序一样,它重现了这个问题。 Xcode >= 7.0 上的测试应用程序挂断但在 Xcode 6.4 上正常工作
测试源下载链接: https://www.sendspace.com/file/r07cln
测试申请的要求是: 1.系统必须安装cocoa pods manager 2. 2.2版本的MagicalRecord框架。
测试应用程序以下列方式工作: 1. 在应用程序启动时,它创建包含 10000 条简单实体记录的测试数据库,并将它们保存到持久存储中。 2. 在应用程序的第一个屏幕中,viewWillAppear 方法:它运行导致死锁的测试。 使用以下算法:
-(NSArray *) entityWithId: (int) entityId inContext:(NSManagedObjectContext *)localContext
{
NSArray * results = [TestEntity MR_findByAttribute:@"id" withValue:[ NSNumber numberWithInt: entityId ] inContext:localContext];
return results;
}
…..
int entityId = 88;
NSManagedObjectContext *childContext1 = [NSManagedObjectContext MR_context];
childContext1.name = @"childContext1";
NSManagedObjectContext *childContext2 = [NSManagedObjectContext MR_context];
childContext2.name = @"childContext2";
NSArray *results = [self entityWithId:entityId inContext: childContext2];
for(TestEntity *d in results)
{
NSLog(@"e from fetchRequest %@ with name = '%@'", d, d.name); /// this line is the reason of the hangup
}
dispatch_async(dispatch_get_main_queue(), ^
{
int entityId2 = 11;
NSPredicate *predicate2 = [NSPredicate predicateWithFormat:@"id=%d", entityId2];
NSArray *a = [ TestEntity MR_findAllWithPredicate: predicate2 inContext: childContext2];
for(TestEntity *d in a)
{
NSLog(@"e from fetchRequest %@ with name = '%@'", d, d.name);
}
});
使用并发类型== NSPrivateQueueConcurrencyType 创建了两个托管对象上下文(请查看魔法记录框架的MR_context 的代码)。两个上下文都有父上下文 并发类型 = NSMainQueueConcurrencyType。从主线程应用程序以同步方式执行获取( MR_findByAttribute 和 MR_findAllWithPredicate 与内部获取请求一起使用 performBlockAndWait )。在第一次 fetch 之后,第二次 fetch 使用 dispatch_async() 在主线程上调度。
因此应用程序挂起。好像发生了死锁,请查看堆栈截图:
这是链接,我的声誉太低,无法发布图像。 https://cdn.img42.com/34a8869bd8a5587222f9903e50b762f9.png)
如果要评论该行
NSLog(@"e from fetchRequest %@ with name = '%@'", d, d.name); /// 这行是挂断的原因
(这是测试项目的 ViewController.m 中的第 39 行)应用程序运行正常。我相信这是因为没有读取测试实体的名称字段。
所以用注释行
NSLog(@"e from fetchRequest %@ with name = '%@'", d, d.name);
使用 Xcode 6.4 和 Xcode 7.0 构建的二进制文件没有任何问题。
带有未注释的行 NSLog(@"e from fetchRequest %@ with name = '%@'", d, d.name);
使用 Xcode 7.0 构建的二进制文件有挂断,使用 Xcode 6.4 构建的二进制文件没有挂断。
我认为问题是由于实体数据的延迟加载而发生的。
对所描述的案例有任何问题吗?如有任何帮助,我将不胜感激。
【问题讨论】:
-
我认为最近的 iOS 9 SDK 存在问题或不兼容,但为了帮助人们解决这个问题,让我们让您的帖子更加清晰。首先,你能把你的例子上传到github吗? (Chrome 不允许我下载)。第二个:删除您对 pod 所做的所有更改。删除未使用的代码,使示例清晰。问题的简短故事是:如果 1)从 -viewWillAppear 分派,并且 2)在分派之前使用了托管对象(触发错误)(就像您在 NSLog 中所做的那样:d.name ) 直接CoreDa也有同样的问题
标签: ios core-data deadlock ios9 magicalrecord