【问题标题】:iOS: Synchronizing access to CoreDataiOS:同步访问 CoreData
【发布时间】:2016-02-08 17:02:39
【问题描述】:

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

【问题讨论】:

  • 您确定需要串行队列吗?如果您在该块内执行不安检查,为什么通过 performBlockAndWait 将两个操作入队会给您带来问题?
  • @Jonah 是的,我是。如果我用一个信号 MOC 运行所有东西 - 没关系。但正如您所见,saveEntry 会为每次调用创建一个 MOC。所以你会有并行操作
  • 糟糕,我应该仔细阅读。与其使用串行队列来创建许多 moc,为什么不共享一个 moc,然后将其用作该队列?
  • 你确定它是安全的吗?我看到 MagicalRecord 为每次保存创建新的上下文

标签: ios multithreading core-data magicalrecord


【解决方案1】:

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

当然要考虑一些复杂情况,如果不了解您的应用的更多信息,我无法提供真正的建议。

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

【讨论】:

  • 非常感谢!我有一个 DB signleton,其中包含所有保存读取相关的逻辑。我猜它会创建一个私有上下文并对其执行所有更改。您确定维护信号上下文并对其执行所有更改是安全的(尽管 Saul Mora 提到了这一事实)?
  • @user1284151 Saul 正在解决一个真实但不相关的问题。 Core Data 最初依赖于NSManagedObjectContexts 的NSConfinementConcurrencyType 每线程限制,但是基于线程的并发可以优化的程度是有限的。现在被 MagicalRecord 采用的首选模式是使用队列限制,它不一定将上下文耦合到单个线程。 MagicalRecord 的contextForCurrentThread 因此不再有用或无效。在任一模型下,共享上下文在其限制范围内都是有效的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多