【问题标题】:Accessing NSManagedObject from background thread从后台线程访问 NSManagedObject
【发布时间】:2012-06-26 07:08:45
【问题描述】:

所以我知道 NSManagedObjects 不是线程安全的,从后台线程获取对象的最佳方法是使用 [context objectWithId:id]; ,因此传递对象 ID 而不是实际对象。

假设我的AppDelegate 中有一个全局NSManagedObject(不是最好的设计模式,只是举例)NSManagedObject *myObject;

从后台线程访问该对象的objectId 是否安全?像这样:

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
        objectId = appDelegate.myObject.objectId;
        //is this thread safe?
}

【问题讨论】:

    标签: iphone objective-c ios cocoa core-data


    【解决方案1】:

    这是不安全的,因为不能保证在 myObject 上调用 objectID 是安全的。您应该在块之外(例如在主线程上)访问 objectID,然后在块中使用它。比如:

    NSManagedObjectID *objectID = appDelegate.myObject.objectId;
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
        // use objectID here.
    }
    

    【讨论】:

    • 我同意您的解决方案,但我需要了解一件事,NSManagedObject 的 objectID 是不可变属性(第一次保存后)。从任何线程访问不可变属性不安全吗?
    • @PushpRaj 一般来说,属性不可变并不能保证线程安全。对于 NSManagedObject,文档非常明确,您不应该将 NSManagedObjects 从一个线程传递到另一个线程,这就是示例代码正在执行的操作(无论您正在访问哪些属性)。没错,实现细节可能意味着从后台线程访问 objectID 是安全的,但肯定不能保证。
    【解决方案2】:

    您需要为您使用的每个线程(历史上)有一个单独的上下文。由于 dispatch_async 不能保证在任何给定线程上运行,因此您需要在块内创建一个上下文。或者,在 iOS 5.0 或更高版本上,NSManagedContext 带有新的并发模式。上下文将创建自己的私有串行队列,供您将块传递给。如果您需要支持 iOS 4.x,那么您可以模仿这种行为。创建一个串行队列,并且只访问该队列中的上下文。

    您不能做任何导致来自两个不同线程的查询或上下文更改的事情,因为它可能会产生竞争条件。

    【讨论】:

      猜你喜欢
      • 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
      相关资源
      最近更新 更多