2012-06-25 34 views
1

因此,我知道NSManagedObjects不是线程安全的,从后台线程获取对象的最佳方式是使用[context objectWithId:id];,因此传递对象标识而不是实际对象。从后台线程访问NSManagedObject

比方说,我有我的AppDelegate全球NSManagedObject(不是最好的设计模式,但只是举例)NSManagedObject *myObject;

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

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

回答

2

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

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

我同意你的解决方案,但我需要了解一件事情, NSManagedObject的objectID是不可变属性(第一次保存后)。是不是可以安全地从任何线程访问不可变属性? – PushpRaj

+1

@PushpRaj一般来说,让一个属性不可变并不能保证线程安全。对于NSManagedObject,文档非常明确,您不应该将NSManagedObjects从一个线程传递到另一个线程,这就是示例代码正在执行的操作(无论您正在访问哪个属性)。你说得对,实现细节*很可能意味着从后台线程访问objectID是安全的,但肯定不能保证。 –

1

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

您可能不会执行任何操作,导致在两个不同线程的上下文中进行查询或更改,因为它可能会创建竞争条件。