iOS:同步对CoreData

时间:2016-02-08 17:02:40

标签: ios multithreading core-data magicalrecord

我是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

1 个答案:

答案 0 :(得分:1)

我会尝试用一个NSManagedObjectContext作为控制机制来实现它。每个上下文都维护一个串行操作队列,因此多个线程可以调用performBlock:performBlockAndWait:而不会有任何并发​​访问的危险(尽管您必须小心上下文的数据在块入队的时间和时间之间的变化最终执行)。只要上下文中的所有工作都在正确的队列上完成(通过performBlock),就不会有从多个线程中排队工作的内在危险。

当然有一些复杂因素需要考虑,如果不了解您的应用程序,我无法提供真正的建议。

  • 什么对象将负责创建此上下文以及如何将其提供给需要它的每个对象?
  • 如果在您的应用中代表一个有意义的状态,那么很难知道该上下文的工作何时“完成”(它的操作队列为空)。
  • 如果您希望在发生错误时丢弃未保存的修改,则在共享上下文中放弃更改会更加困难(您需要实际还原这些更改,而不是简单地丢弃上下文而不保存)。