从后台队列调用时,核心数据 NSManagedObjectContext 保存永远不会返回
Posted
技术标签:
【中文标题】从后台队列调用时,核心数据 NSManagedObjectContext 保存永远不会返回【英文标题】:Core Data NSManagedObjectContext save never returns when called from a background queue 【发布时间】:2016-01-08 00:06:41 【问题描述】:当我在来自单独的后台队列的 NSManagedObjectContext
的私有队列中调用 save()
时,我的应用程序(单元测试)正在停止。它是一个普通的 Core Data 堆栈(具有用于单元测试的内存中持久存储)。
私有队列上下文的重点不就是您不应该关心操作来自哪个队列吗?我应该如何解决这个问题?
我无法单独重现它,但这是我的设置的粗略想法(伪 Swift,跨多个类的压缩调用):
let store = inMemoryStoreCoordinator()
let mainContext = NSManagedObjectContext(concurrencyType: .MainQueueConcurrencyType)
mainContext.persistentStoreCoordinator = store
let childContext = NSManagedObjectContext(concurrencyType: .PrivateQueueConcurrencyType)
childContext.parentContext = mainContext
let q = NSOperationQueue()
let group = dispatch_group_create()
q.addOperationWithBlock
dispatch_group_enter(group)
childContext.performBlock
try! childContext.save()
dispatch_group_leave(group)
dispatch_group_wait(group, DISPATCH_TIME_FOREVER)
【问题讨论】:
添加持久存储协调器会改善情况吗? @pbasdf 不,它没有。我更新了问题,提到我遇到问题的实际代码有一个 PSC。 我试了几次,有时我只得到“a”;有时是“a”和“b”。我认为这可能只是一个时间问题——前台处理在异步之前完成。如果在 dispatch_async 之后添加一些处理,您会同时看到“a”和“b”。 @pbasdf 很有趣,这就解释了为什么操场会表现出这种行为。添加XCPlaygroundPage.currentPage.needsIndefiniteExecution = true
即可。我需要想出一个更好的测试用例。
【参考方案1】:
这可能有几个原因,但我们无法从提供的代码中推断出任何原因。幸运的是,应该很容易调试,只需在死锁(很可能)发生后暂停调试器,看看什么在等待什么。这可能是一个上下文合并僵局,我会把钱放在上面。
【讨论】:
谢谢,但我已经尝试过了,调试器不会暂停。一旦它进入那个状态,我必须停止这个过程。 啊,看到你的更新了。忽略我的回答,留给后人 我在try save()
行设置了一个断点,然后跳过。几秒钟后(此时显然已经死锁,因为没有数据要保存),我点击暂停按钮(或点击 ^⌘Y),但没有任何效果。
我需要更新问题,因为我的操场示例实际上不再演示该问题。我发现它没有等待异步调用完成。
感谢您的帮助,但我想通了。暂停不起作用是非常糟糕的。我猜当主线程出现死锁时会发生这种情况?【参考方案2】:
我意识到是什么导致了僵局。我正在使用调度组来锁定主线程,显然当子上下文保存到其父上下文(主队列上下文)时,这会导致死锁。
【讨论】:
以上是关于从后台队列调用时,核心数据 NSManagedObjectContext 保存永远不会返回的主要内容,如果未能解决你的问题,请参考以下文章