2012-07-20 52 views
1

因爲兩天我試圖讓Core Data與多個線程一起工作。我嘗試使用標準線程限制方法與NSOperations,合併通知,使用objectWithId,每個線程的上下文字典,仍然我得到奇怪的死鎖,不一致性異常和一堆其他討厭的東西。這讓我瘋狂......另外,我無法找到關於如何在兩個線程中管理上下文的單個示例或解釋,當兩個線程都可以對共享持久存儲進行更改時...使用併發類型保存上下文時發生死鎖NSPrivateQueueConcurrencyType

我試圖使用新的iOS 5方法,這應該是更容易,但我仍然得到錯誤。第一個問題是保存上下文時發生死鎖。我刪除了所有不必要的代碼並執行時該代碼足夠快(通過快速敲擊按鈕)STIL得到死鎖:

NSManagedObjectContext *context = [StoreDataRetriever sharedRetriever].managedObjectContext; 

    for (int i = 0; i < 5; i++) {    
     NSError *error = nil; 
     NSLog(@"Main thread: %@, is main? %d", [NSThread currentThread], [NSThread isMainThread]); 
     BOOL saveOK = [context save:&error]; 

     if (!saveOK) { 
      NSLog(@"ERROR!!! SAVING CONTEXT IN MAIN"); 
     } 

     [context performBlock:^{ 

      NSLog(@"Block thread: %@", [NSThread currentThread]); 

      NSError *error = nil; 
      BOOL savedOK = NO; 

      savedOK = [context save:&error]; 

      if (!savedOK) { 
       NSLog(@"ERROR!!! SAVING CONTEXT IN BLOCK"); 
      } 
     }]; 
    } 

有沒有其他對數據庫的更改,什麼都沒有,只有環境保存。這段代碼有什麼問題?它應該是什麼樣子?

注意:[StoreDataRetriever sharedRetriever] .managedObjectContext是在appDelegate中使用initWithConcurrencyType:NSPrivateQueueConcurrencyType創建的。

回答

2

這段代碼是怎麼回事?您正在同步保存線程的上下文,然後您在上下文專用隊列上安排保存。 5次。所以基本上,你可能有兩個保存操作,一個同步和一個異步,彼此碰撞。

這顯然是一個問題。您不應該在該隊列之外使用專用隊列保存上下文。只要上下文隊列中沒有調度塊,它將與當前上下文實現一起工作。但這是錯誤的。

… 
for (int i = 0; i < 5; i++) {    
    NSLog(@"Main thread: %@, is main? %d", [NSThread currentThread], [NSThread isMainThread]); 
    __block NSError *error = nil; 
    __block BOOL saveOK = YES; 
[context performBlockAndWait: ^{ 
    saveOK = [context save: &error]; 
}]; 

    if (!saveOK) { 
     NSLog(@"ERROR!!!"); 
    } 
    … 

與該代碼,您同步執行保存操作,並肯定在同一個線程 - 感謝GCD - 節約上下文切換和同步的東西,而不必同時在該環境中運行的兩個操作的任何風險時間。

使用NSMainQueueConcurrencyType時有同樣的規則,但有一個例外。該隊列僅限於主線程和主線程。您可以使用任何具有performBlock和performBlockAndWait(如NSPrivateQueueConcurrencyType)的線程的主隊列在上下文中調度塊,並且(例外情況:)您可以直接在主線程上使用上下文。

NSConfinementConcurrencyType將上下文綁定到特定的線程,並且不能使用GCD或塊來處理這樣的上下文,只能處理綁定的線程。到目前爲止,使用該併發模型的理由很少。如果你必須使用它,但是如果你不一定要,那就不要。


編輯

這裏是關於多contextes設置一個非常漂亮的文章:http://www.cocoanetics.com/2012/07/multi-context-coredata/

+0

所以它並不能幫助那麼多在我的現實世界中的問題:我需要做的耗時的計算在NSManagedbjects的背景中,同時保持UI響應並在主線程上執行一些操作(創建新的託管對象,更改數量等以響應用戶點擊)。我仍然必須使用禁閉或可能創建子上下文?呃... – 2012-07-23 07:57:27

+0

孩子們比較便宜。如果你的計算量很大,那麼兒童背景的成本幾乎沒有。所以是的,這是一個很好的方法,您可以使用performBlock爲您計劃爲特定的子上下文計算特定的子上下文,並將修改保存在最後或者有意義時。這裏是關於那個話題的文章:http://www.cocoanetics.com/2012/07/multi-context-coredata/ – 2012-07-23 08:38:10

+0

不幸的是,我正在修改的現有代碼是使用StoreDataRetriever單例對象模式調用此對象深深地埋在代碼中。在這個階段很難改變它,所以我認爲我會採用舊的禁閉方法。我只需要找出我的代碼有什麼問題... – 2012-07-23 10:27:45

相關問題