【问题标题】:Core Data NSManagedObjectContext save never returns when called from a background queue从后台队列调用时,核心数据 NSManagedObjectContext 保存永远不会返回
【发布时间】: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 即可。我需要想出一个更好的测试用例。

标签: multithreading swift core-data nsoperationqueue


【解决方案1】:

这可能有几个原因,但我们无法从提供的代码中推断出任何原因。幸运的是,应该很容易调试,只需在死锁(很可能)发生后暂停调试器,看看什么在等待什么。这可能是一个上下文合并僵局,我会把钱放在上面。

【讨论】:

  • 谢谢,但我已经尝试过了,调试器不会暂停。一旦它进入那个状态,我必须停止这个过程。
  • 啊,看到你的更新了。忽略我的回答,留给后人
  • 我在try save() 行设置了一个断点,然后跳过。几秒钟后(此时显然已经死锁,因为没有数据要保存),我点击暂停按钮(或点击 ^⌘Y),但没有任何效果。
  • 我需要更新问题,因为我的操场示例实际上不再演示该问题。我发现它没有等待异步调用完成。
  • 感谢您的帮助,但我想通了。暂停不起作用是非常糟糕的。我猜当主线程出现死锁时会发生这种情况?
【解决方案2】:

我意识到是什么导致了僵局。我正在使用调度组来锁定主线程,显然当子上下文保存到其父上下文(主队列上下文)时,这会导致死锁。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-12-06
    • 2017-07-26
    • 1970-01-01
    相关资源
    最近更新 更多