【问题标题】:Coredata concurrency issuesCoredata 并发问题
【发布时间】:2016-05-10 14:36:30
【问题描述】:

我有一个具有私有上下文的 NSOperation 子类,以及一个在主队列上具有上下文的单例数据管理器类。所有的 UI 和 crud 操作都由这个单例类完成,而从云工具包中的后台获取则由 NSOperation 子类完成。有几个疑问如下。

  1. 以下是我在 NSoperation 子类中的代码。下面的代码会造成死锁吗?

    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)")
    
            }
    
          })
        }
      }
    }
    
  2. 如果我有另一个使用此类 NSManagedOBject 的单例类,我是否需要通过 ID 传递它们?

【问题讨论】:

    标签: ios objective-c multithreading core-data deadlock


    【解决方案1】:

    首先,您需要在运行时参数中打开-com.apple.CoreData.ConcurrencyDebug 1。这将有助于确保您在正确的线程/队列上调用所有内容。

    其次,您正在对选项进行大量强制解包,这是一个非常糟糕的习惯。最好正确解包它们或使用可选解包。

    第三,当你暂停调试器时会发生什么?它正在暂停的代码行在哪里?你在哪个队列上?

    仅打开并发调试很可能会向您显示您的问题。

    项目 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)")
        }
    }
    

    这消除了对可选选项的强制解包,如果在任何一种情况下都有一个错误,则将两个错误都打印出来。

    更新

    另外,一些开发者说像上面这样嵌套的 performblockandwait 会导致死锁。

    performBlockAndWait 永远不会导致死锁。它比这更聪明。

    • 如果您要从一个队列转到另一个队列,那么您希望每个队列都像代码描述的那样阻塞并等待。
    • 如果您在正确的队列中并调用了 performBlockAndWait,那么该调用实际上是无操作的,并且将不会死锁

    【讨论】:

    • 谢谢马库斯,嵌套的 performblockandwait 会造成死锁问题吗?有人说使用嵌套的 performblockandwait 不好?
    • 1.打开运行时并发变量,虽然我知道帮助同步的单例类正在另一个线程上使用托管对象,但它们不在主线程上,但调试变量仍然存在问题。 2. 感谢 marcus 的代码格式化,并将使用 optional 的正确解包。 3. 还有一些开发者说像上面这样嵌套的 performblockandwait 会导致死锁。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-03-20
    • 2017-05-01
    • 1970-01-01
    • 1970-01-01
    • 2015-09-04
    • 2011-06-07
    • 2012-10-26
    相关资源
    最近更新 更多