【问题标题】:Deadlock using AFIncrementalStore and NSFetchedResultsController使用 AFIncrementalStore 和 NSFetchedResultsController 的死锁
【发布时间】:2013-02-25 22:44:51
【问题描述】:

这几天我一直在为此苦苦挣扎,我终其一生都无法弄清楚发生了什么。我对 Core Data 很熟悉,但我知道它足以避免死锁情况。然而,对于这个项目,我决定尝试合并 AFIncrementalStore。我构建了一个示例项目来测试 APIClient 以便适当地映射键/值而不会弄乱我的实际项目。它完美无缺。

现在我在我的实际项目中使用它并且事情很挑剔。 NSFetchedResultsController 用于被推离屏幕的 UITableViewController(类似于 Facebook 应用程序的滑动菜单)。大约 50% 的时间我不会陷入僵局。我已确保 NSFetchedResultsController managedObjectContext 与我的 AppDelegate 相同。几乎所有的设置都与 AFIncrementalStore 示例相同。甚至我用来测试用法的示例项目也能完美运行。

这是我在死锁期间暂停时调试导航器的图像。看起来问题出在 AFIncrementalStore 的背景上下文和主线程的上下文之间。但是我不知道该怎么做,因为我没有编写 AFIncrementalStore 并且只是退出现有的文档/示例。

编辑:添加第二个线程的回溯

thread #2: tid = 0x2103, 0x925d180e libsystem_kernel.dylib`semaphore_wait_trap + 10
frame #0: 0x925d180e libsystem_kernel.dylib`semaphore_wait_trap + 10
frame #1: 0x0258cf08 libdispatch.dylib`_dispatch_thread_semaphore_wait + 16
frame #2: 0x0258ab3a libdispatch.dylib`_dispatch_barrier_sync_f_slow + 149
frame #3: 0x0258aa5c libdispatch.dylib`dispatch_barrier_sync_f + 37
frame #4: 0x00b64c8b CoreData`_perform + 187
frame #5: 0x00b67659 CoreData`-[NSManagedObjectContext(_NestedContextSupport) managedObjectContextDidUnregisterObjectsWithIDs:] + 73
frame #6: 0x00bdf2db CoreData`__97-[NSManagedObjectContext(_NestedContextSupport) managedObjectContextDidUnregisterObjectsWithIDs:]_block_invoke_0 + 75
frame #7: 0x00b64cc1 CoreData`internalBlockToNSManagedObjectContextPerform + 17
frame #8: 0x0259b014 libdispatch.dylib`_dispatch_client_callout + 14
frame #9: 0x0258ad5f libdispatch.dylib`_dispatch_barrier_sync_f_invoke + 58
frame #10: 0x0258aaa3 libdispatch.dylib`dispatch_barrier_sync_f + 108
frame #11: 0x00b64c8b CoreData`_perform + 187
frame #12: 0x00b67659 CoreData`-[NSManagedObjectContext(_NestedContextSupport) managedObjectContextDidUnregisterObjectsWithIDs:] + 73
frame #13: 0x00b71c8c CoreData`-[NSManagedObjectContext(_NSInternalAdditions) _disposeObjects:count:notifyParent:] + 444
frame #14: 0x00b71305 CoreData`-[NSManagedObjectContext(_NSInternalAdditions) _dispose:] + 597
frame #15: 0x00b70e15 CoreData`-[NSManagedObjectContext _dealloc__] + 325
frame #16: 0x00bd872f CoreData`internalBlockToDeallocNSManagedObjectContext + 79
frame #17: 0x0259b014 libdispatch.dylib`_dispatch_client_callout + 14
frame #18: 0x0258b418 libdispatch.dylib`_dispatch_queue_drain + 239
frame #19: 0x0258b2a6 libdispatch.dylib`_dispatch_queue_invoke + 59
frame #20: 0x0258c280 libdispatch.dylib`_dispatch_root_queue_drain + 231
frame #21: 0x0258c450 libdispatch.dylib`_dispatch_worker_thread2 + 39
frame #22: 0x971cde12 libsystem_c.dylib`_pthread_wqthread + 441

【问题讨论】:

  • 我之前没用过AFIncrementalStore,但是需要手动将AFIncrementalStore上下文合并到主AppDelegate上下文吗?当 fetchedresultscontroller 与某种核心数据导入并行工作时,这是一种常见的核心数据死锁。

标签: ios multithreading core-data deadlock afincrementalstore


【解决方案1】:

此问题并非特定于使用 AFIncrementalStore。我们在使用嵌套上下文和 NSFetched 结果控制器时遇到了同样的事情。

子上下文和兄弟上下文不需要使用相同的并发类型,也不需要使用相同的线程。但是,您获取的结果控制器必须在其托管对象上下文使用的同一线程上使用,调试导航器中的线程 2 NSManagedObjectContext Queue 让我认为这可能是一个线程问题。

如果这是您的主要上下文,有时这就像像这样包装您的 fetth 一样简单

dispatch_async(dispatch_get_main_queue(), ^{ [resultsController performFetch:nil]; });

或者对于真正的偏执狂

[_resultsController.managedObjectContext performBlock:^{
    [_resultsController performFetch:nil];
}];

关于这些死锁的内容很多,请尝试使用 herehere 获取堆栈溢出帖子。

【讨论】:

  • 欣赏答案。我尝试了您的解决方案并浏览了所有链接。最终登陆一篇关于目前如何使用子 MOC 的文章非常糟糕。我现在将 AFIncrementalStore 的子 MOC 更改为使用 NSMainQueueConcurrencyType 并且它很稳定,但是我根本不喜欢这个修复。
【解决方案2】:

无论如何,我都不是 CoreData 专家,所以对此持保留态度。

看起来,您可能正在使用 NSPrivateQueueConcurrencyType。似乎 AFIncrementalStore 正在使用主队列进行同步。这在你的控制之下吗?

您可以尝试将您的 NSManagedObjectContext 切换为 NSMainQueueConcurrencyType 看看是否有帮助?

现在,如果我是对的,并且您使用的是 NSPrivateQueueConcurrencyType,那么您可能是出于性能原因这样做。所以,这可能不是一个很好的长期解决方案......

【讨论】:

  • 我实际上是在我的 AppDelegate 中使用 NSMainQueueConcurrencyType 设置我的 MOC。 AFIncrementalStore 中有 2 个位置使用 NSPrivateQueueConcurrencyType(这些是缩写)初始化 MOC:-newValuesForObjectWithID、-newValueForRelationship 和 -executeFetchRequest。 -newValueForRelationship 是在锁定之前调用的唯一方法。我将该方法中的行更改为 NSMainQueueConcurrencyType 并且无法重现崩溃。然而这让我很紧张,修改我没有写的代码。
  • 是的,我看了之后的代码,也看到了。我认为@tapi 的建议听起来更明智,所以我赞成。我对 CoreData 同步模型的了解不够多,无法发表更多评论。
  • 实际上,您的解决方案使我获得了稳定的构建。我不认为它是一个修复,因为它使用主队列进行提取,但是嘿,它的工作。现在。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-01-03
  • 2015-10-26
  • 2017-07-31
  • 2019-04-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多