核心数据并发问题
Coredata concurrency issues
我有一个 NSOperation subclass,它有自己的私有上下文,还有一个单例数据管理器 class,它在主队列上有一个上下文。所有 UI 和 crud 操作都是由这个单例 class 完成的,而从云工具包的后台获取是由 NSOperation subclass 完成的。几乎没有疑问如下。
以下是我在 NSoperation subclass.Can 下面的代码创建死锁的代码?
self.localStoreMOC?.performBlockAndWait({ () -> Void in
//Long process of fetching data from cloud and pushing changes to cloud happens here.
var error:NSErrorPointer = nil
if self.localStoreMOC!.hasChanges
{
do
{
try self.localStoreMOC!.save()
}
catch let error1 as NSError
{
error.memory = error1
}
if error == nil
{
self.localStoreMOC!.parentContext!.performBlockAndWait({
do
{
try self.localStoreMOC!.parentContext!.save()
}
catch let error1 as NSError
{
print("wasSuccessful error1 \(error1)")
}
})
}
}
}
如果我有另一个单例 class 使用这个 class NSManagedOBject 我需要通过 ID 传递它们吗?
首先,您需要在 运行 时间参数中打开 -com.apple.CoreData.ConcurrencyDebug 1
。这将有助于确保您在正确的 thread/queue.
上调用所有内容
其次,您正在对可选项进行大量强制解包,这是一个非常糟糕的习惯。最好正确解包或使用可选解包。
第三,当你暂停调试器时会发生什么?它暂停的代码行在哪里?您在哪个队列中?
只需打开并发调试就很可能会显示您的问题。
项目 2
如果您想将对 NSManagedObject
的引用从一个上下文传递到另一个上下文,那么是的,您需要使用 NSManagedObjectID
,因为 NSManagedObject
传递不安全上下文之间。
代码格式化
正在调整格式,您可能对结果感兴趣:
guard let local = localStoreMOC else { fatalError("Local store is nil") }
guard let parent = local.parentContext else { fatalError("Parent store is nil") }
local.performBlockAndWait {
//Long process of fetching data from cloud and pushing changes to cloud happens here.
if !local.hasChanges { return }
do {
try local.save()
parent.performBlockAndWait {
do {
try parent.save()
} catch {
print("wasSuccessful error1 \(error)")
}
}
} catch {
print("Failed to save local: \(error)")
}
}
这消除了可选值的强制解包,并且如果在任何一种情况下都出现错误,则会打印出两个错误。
更新
Also, some developers, say that nested performblockandwait like above will cause deadlock.
performBlockAndWait
永远不会造成死锁。它比那个更聪明。
- 如果您要从一个队列转到另一个队列,那么您希望每个队列都像代码描述的那样阻塞并等待。
- 如果您在正确的队列中并调用了
performBlockAndWait
,那么该调用实际上是空操作,并且会 NOT 死锁
我有一个 NSOperation subclass,它有自己的私有上下文,还有一个单例数据管理器 class,它在主队列上有一个上下文。所有 UI 和 crud 操作都是由这个单例 class 完成的,而从云工具包的后台获取是由 NSOperation subclass 完成的。几乎没有疑问如下。
以下是我在 NSoperation subclass.Can 下面的代码创建死锁的代码?
self.localStoreMOC?.performBlockAndWait({ () -> Void in //Long process of fetching data from cloud and pushing changes to cloud happens here. var error:NSErrorPointer = nil if self.localStoreMOC!.hasChanges { do { try self.localStoreMOC!.save() } catch let error1 as NSError { error.memory = error1 } if error == nil { self.localStoreMOC!.parentContext!.performBlockAndWait({ do { try self.localStoreMOC!.parentContext!.save() } catch let error1 as NSError { print("wasSuccessful error1 \(error1)") } }) } } }
如果我有另一个单例 class 使用这个 class NSManagedOBject 我需要通过 ID 传递它们吗?
首先,您需要在 运行 时间参数中打开 -com.apple.CoreData.ConcurrencyDebug 1
。这将有助于确保您在正确的 thread/queue.
其次,您正在对可选项进行大量强制解包,这是一个非常糟糕的习惯。最好正确解包或使用可选解包。
第三,当你暂停调试器时会发生什么?它暂停的代码行在哪里?您在哪个队列中?
只需打开并发调试就很可能会显示您的问题。
项目 2
如果您想将对 NSManagedObject
的引用从一个上下文传递到另一个上下文,那么是的,您需要使用 NSManagedObjectID
,因为 NSManagedObject
传递不安全上下文之间。
代码格式化
正在调整格式,您可能对结果感兴趣:
guard let local = localStoreMOC else { fatalError("Local store is nil") }
guard let parent = local.parentContext else { fatalError("Parent store is nil") }
local.performBlockAndWait {
//Long process of fetching data from cloud and pushing changes to cloud happens here.
if !local.hasChanges { return }
do {
try local.save()
parent.performBlockAndWait {
do {
try parent.save()
} catch {
print("wasSuccessful error1 \(error)")
}
}
} catch {
print("Failed to save local: \(error)")
}
}
这消除了可选值的强制解包,并且如果在任何一种情况下都出现错误,则会打印出两个错误。
更新
Also, some developers, say that nested performblockandwait like above will cause deadlock.
performBlockAndWait
永远不会造成死锁。它比那个更聪明。
- 如果您要从一个队列转到另一个队列,那么您希望每个队列都像代码描述的那样阻塞并等待。
- 如果您在正确的队列中并调用了
performBlockAndWait
,那么该调用实际上是空操作,并且会 NOT 死锁