2010-01-26 98 views
55

我試圖以多線程方式使用核心數據。 我只是想在後臺下載新數據的同時顯示應用程序和以前下載的數據。 這應該讓用戶在更新過程中訪問應用程序。核心數據多線程應用程序

我有一個使用委託(並顯示進度)異步下載文件的NSURLConnection,然後我使用XMLParser解析新數據,並在獨立的上下文中創建新的NSManagedObjects,使用它自己的persistentStore並使用單獨的線程。

問題是,在顯示它的同一上下文中創建新對象時可能會拋出BAD_INSTRUCTION異常。 因此,我決定爲新數據使用單獨的上下文,但我無法找到一種方法來完成後將所有對象移動到其他上下文。

保羅又名SlowTree

回答

138

The Apple Concurrency with Core Data documentation是開始的地方。仔細閱讀......我誤會了很多次!

基本規則是:

  1. 使用一個NSPersistentStoreCoordinator每個程序。每個線程你都不需要它們。
  2. 每個線程創建一個NSManagedObjectContext
  3. 切勿將線上的NSManagedObject傳遞給其他線程。
  4. 而是通過-objectID獲取對象ID並將其傳遞給另一個線程。

更多規則:

  1. ,請務必保存對象進店獲取對象ID之前。在保存之前,它們是暫時的,並且您無法從其他線程訪問它們。
  2. 如果您對來自多個線程的管理對象進行更改,請注意合併策略。
  3. NSManagedObjectContext-mergeChangesFromContextDidSaveNotification:是有幫助的。

但讓我再說一遍,請仔細閱讀文檔!這真的很值得!

+1

我發現CoreDataBooks融合背景下的一個很好的例子(mergeChangesFromContextDidSaveNotification)。 非常感謝。 祝您有愉快的一天。 保羅又名SlowTree – SlowTree 2010-01-26 10:22:45

+0

哦,謝天謝地。我讀這個解決了我的問題。 正在後臺線程中導入大量數據並獲取大量不可預知的異常。 在後臺線程中實例化上下文而不是傳遞它似乎修復了我的isses。 – tobyc 2010-05-25 03:41:03

+2

本文檔尚未更新,以利用iOS 5中非常重要的改進 - 我在我的答案中鏈接的視頻現在是更好的參考。 – JosephH 2012-08-05 08:24:35

2

我希望這可以幫助所有在多線程環境中使用核心數據解決問題的人們。

在蘋果文檔中查看「Top Songs 2」。通過這段代碼,我接過了Matrix的「紅色藥丸」,並且發現了一個新的世界,沒有雙重自由錯誤,沒有錯誤。 :D

希望這會有所幫助。

Paolo

p.s. 非常感謝Yuji,在你上面描述的文檔中,我找到了這個例子。

73

目前[2015年5月] Apple Concurrency with Core Data documentation充其量是誤導性的,因爲它不包括iOS 5中的任何增強功能,因此不再顯示同時使用核心數據的最佳方式。iOS 5中有兩個非常重要的更改 - 父上下文和新併發/線程類型。

我還沒有找到全面涵蓋這些新功能的書面文檔,但WWDC 2012 video "Session 214 - Core Data Best Practices"確實很好地解釋了這一點。

Magical Record使用這些新功能,可能值得一看。

真正的基礎仍然是一樣的 - 你仍然可以只使用託管對象的管理對象上下文創建線程。

您現在可以使用[moc performBlock:]在右側線程上運行代碼。

沒有必要使用mergeChangesFromContextDidSaveNotification:anymore;而是創建一個子上下文來進行更改,然後保存子上下文。保存子上下文將自動將更改推送到父上下文中,並將更改保存到磁盤,只需在其線程中執行父上下文的保存即可。

對於這個工作,你必須創建一個併發類型父上下文,如:

mainManagedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType]; 

然後在後臺線程:

context = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSConfinementConcurrencyType]; 
[context setParentContext:mainManagedObjectContext]; 

<... perform actions on context ...> 

NSError *error; 
if (![context save:&error]) 
{ 
    <... handle error ...> 
} 
[mainManagedObjectContext performBlock:^{ 
    NSError *e = nil; 
    if (![mainContext save:&e]) 
    { 
     <... handle error ...> 
    } 
}]; 
+0

雖然WWDC鏈接似乎是錯誤的.. – Philip007 2012-10-01 00:51:26

+7

Upvote for up-to日期信息。 SO應該實施機制來促進與新技術發展相關的答案,並淡化那些過時的被接受的答案。感謝您推薦Magic Record框架。它的文檔看起來非常好。我可能會在稍後嘗試。 – Philip007 2012-10-01 00:53:55

+0

與您的代碼片段相反,UIManagedDocument默認在專用隊列中創建其父上下文,並在主隊列中創建子上下文。任何想法爲什麼蘋果這樣做?這是完全武斷的嗎? – Philip007 2012-10-01 00:56:45