2

我有3個MOC。撤消管理器和多個MOC

  1. MainThread MOC顯示的東西(帶的UndoManager)
  2. 背景保存MOC來保存數據到光盤(連接到存儲)
  3. Backgorund更新MOC從服務器下載數據,分析它並保存後

他們是親子關係。

  1. 背景更新 - > 1. MainThread - >背景保存(存儲)

現在,當我從後臺我需要在mainthread禁用的UndoManager所以他們無法撤消下載數據 - 這可能是用戶正在同時編輯某些內容的情況。

現在問題是如果這是正確的。我在後臺更新線程代碼

//create child background context which is child of 1. MainThread 
NSManagedObjectContext* context = [[AppManager sharedAppManager] createChildManagedObjectContext]; 
//I'M DOING ALL CHANGES ON DATA HERE 
[context.parentContext.undoManager disableUndoRegistration]; //disable undo on main thread 
[context save:nil]; //save changes to background thread 
[context.parentContext save:nil]; //save changes to main thread 
[context.parentContext processPendingChanges]; //process changes on main thread 
[context.parentContext.parentContext save:nil]; //save data to disc on 3. save-thread 
[context.parentContext.undoManager enableUndoRegistration]; //enable undo again 

積木,它看起來像:

[context.parentContext performBlockAndWait:^{ 
      [context.parentContext.undoManager disableUndoRegistration]; 

      [context performBlockAndWait:^{ 
       [context save:nil]; 
      }]; 

      [context.parentContext save:nil]; 
      [context.parentContext processPendingChanges]; 

      [context.parentContext performBlockAndWait:^{ 
       [context.parentContext.parentContext save:nil]; 
      }]; 

      [context.parentContext.undoManager enableUndoRegistration]; 
     }]; 

我這麼問是因爲偶爾我得到了一些不一致的崩潰,我真的不能找到一個理由對於那些。

回答

3

首先,關於發佈代碼的一些基本觀察。

  1. 只應用戶performBlockAndWait在絕對必要的...這是幾乎從來沒有。

  2. 您在子上下文中調用performBlockAndWait,而在父上下文中調用performBlockAndWait。你應該從來沒有做到這一點。

  3. 使用performBlockAndWait在具有專利上下文的上下文中調用​​幾乎可以保證不會做你認爲它的工作。它所做的只是保存到父上下文。

  4. 您在performBlockAndWait內調用performBlockAndWait,而在同一上下文中調用performBlockAndWait。因爲這個電話是可重入的,所以沒什麼不對。但是,另一個線索是您的CD堆棧管理有問題。

現在,一些建議可能會有所幫助。

在你的情況下,我會建議改變你的MOC層次結構。將專用隊列MOC保留爲主隊列MOC的父代。這可以讓您的數據庫更改異步完成。那裏沒有錯。請記住,您必須將調用​​級聯到父級,或者計劃一次保存,因爲保存主MOC只會將其數據複製到父級上下文,而不會觸及底層數據庫。

但是,我會把這個背景MOC作爲主要MOC的孩子去除。現在,你根本不必擔心撤銷管理器,你可以放棄它。

說到撤銷管理器,我發現最好的撤銷管理器是一個子上下文。我只是創建一個作爲主要背景的孩子的背景,在那裏做所有我的更改。如果更改被放棄,只需刪除上下文。一切都沒有完成。您可以在該上下文中安裝撤消管理器以進行增量撤銷管理。

現在,如何處理正在做某種類型的異步更新(可能來自某個Web服務)的背景上下文。我建議:

  1. 設置它的父母與主要的MOC相同。您需要刷新主要MOC,以更改父級。這具有缺點,即對數據庫的任何更新都通過相同的父MOC進行同步,從而爲主MOC提取更多機會等待。

  2. 將它直接連接到持久存儲協調器,並使用通知合併更改。

最後,重新審視你的設計,看看你是否可以通過異步調用。在極其罕見的情況下,您真的應該能夠撥打performBlock,並且只能撥打performBlockAndWait

+0

嗨,謝謝你的提示。我正在使用performBlockAndWait,因爲我在壓力測試應用程序期間可以產生一些崩潰。在主線程中進行壓力測試EDIT/SAVE時,在背景中進行更新。隨着performBlock UndoManager進入一些不穩定的狀態,並在該過程中崩潰。我會通讀您的評論,並根據您的建議重新考慮我的解決方案 - 我可能會對此有所疑問,但需要先分析它:) –

+0

如果'performBlockAndWait'可以防止崩潰......這意味着您在同步問題中其他可能在不阻礙操作的情況下解決的領域。 –

+0

接受答案 - 花了我一段時間找到解決方案,但我最終扔掉undomanager和做的東西在單獨的上下文,我扔掉了,如果用戶取消。這解決了我的大部分問題,thx的想法。 –