我是CoreData的新手,正在尝试创建一个简单的应用程序。
假设我有一个功能:
func saveEntry(entry: Entry) {
let moc = NSManagedObjectContext(concurrencyType: .NSPrivateQueueConcurrencyType)
moc.parentContext = savingContext
moc.pefrormBlockAndWait {
// find if MOC has entry
// if not => create
// else => update
// saving logic here
}
}
它可能会带来一个问题:如果我从两个线程中调用
saveEntry
,则传递相同的条目将对其进行复制。因此,我已将串行队列添加到我的数据库适配器中,并按照以下方式进行操作:func saveEntry(entry: Entry) {
dispatch_sync(serialDbQueue) { // (1)
let moc = NSManagedObjectContext(concurrencyType: .NSPrivateQueueConcurrencyType)
moc.parentContext = savingContext
moc.pefrormBlockAndWait { // (2)
// find if MOC has entry
// if not => create
// else => update
// saving logic here
}
}
}
它运行良好,直到我想添加另一个接口功能为止:
func saveEntries(entries: [Entry]) {
dispatch_sync(serialDbQueue) { // (3)
let moc = NSManagedObjectContext(concurrencyType: .NSPrivateQueueConcurrencyType)
moc.parentContext = savingContext
moc.pefrormBlockAndWait {
entries.forEach { saveEntry($0) }
}
}
}
现在,我陷入了僵局:1将在serialDbQueue上被调用并等待保存完成。 2将在专用队列上被调用并等待3。3正在等待1。
那么处理同步访问的正确方法是什么?据我了解,保留一个MOC并对其进行保存是不安全的,原因如下:http://saulmora.com/coredata/magicalrecord/2013/09/15/why-contextforcurrentthread-doesn-t-work-in-magicalrecord.html
最佳答案
我将尝试使用单个NSManagedObjectContext
作为控制机制来实现。每个上下文都维护一个串行操作队列,因此多个线程可以调用performBlock:
或performBlockAndWait:
而没有并发访问的危险(尽管您必须注意在将数据块放入队列与最终执行之间上下文的数据更改)。只要上下文中的所有工作都在正确的队列上完成(通过performBlock
),就不会从多个线程中排队工作。
当然,要考虑一些复杂因素,如果不了解您的应用程序,我将无法提供真正的建议。
哪个对象将负责创建此上下文,如何将其提供给每个需要它的对象?
使用共享上下文,就很难知道何时在该上下文上完成的工作(它的操作队列为空)是否代表应用程序中有意义的状态。
使用共享上下文,如果您想在发生错误时放弃未保存的修改,则更难放弃更改(您需要实际还原这些更改,而不是简单地放弃而不保存上下文)。