2012-06-25 40 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,那麼您可以在此行爲之後進行建模。創建一個串行隊列,並只能訪問該隊列中的上下文。

您可能不會執行任何操作,導致在兩個不同線程的上下文中進行查詢或更改,因爲它可能會創建競爭條件。