2011-02-07 127 views
5

我目前正在使用NSPersistentDocument子類,它使用NSOperation在後臺導入數據。根據文檔,我在保存後臺任務後觀察NSManagedObjectContextDidSaveNotification,並在主線程中使用-mergeChangesFromContextDidSaveNotification:將通知傳播到NSManagedObjectContext核心數據和NSOperation

一切工作正常,但它爲將數據導入新文檔的用戶呈現了一個奇怪的工作流程。他們需要在導入之前保存一個空文檔(否則-save:失敗,因爲該文檔沒有配置NSPersistentStoreCoordinator的URL)。除了某種「新文檔設置」嚮導之外,我沒有看到任何解決方法確保-writeToURL:ofType:forSaveOperation:originalContentsURL:error:在導入之前被調用。

此外,似乎在後臺導入任務排除在主線程上使用NSUndoManager。 (我假設跨線程共享託管對象上下文的撤銷管理器是不安全的。)從用戶的角度來看,無法撤消在導入過程中創建的所有新對象。

我已經閱讀了核心數據編程指南和Marcus Zarra的書,但我仍然對這個框架的這方面不熟悉。希望我忽略了一些事情:如果沒有,我會使我的應用適應這些限制(Core Data的好處遠遠超過這些用戶界面限制。)

感謝您的時間!

-

基於以下彼得Hosey的建議下,我加入了下面的代碼創建之前進口的臨時持久性存儲:

NSPersistentStoreCoordinator *persistentStoreCoordinator = [self.managedObjectContext persistentStoreCoordinator]; 
if ([[persistentStoreCoordinator persistentStores] count] == 0) { 
    // create an in-memory store to use temporarily 
    NSError *error; 
    NSPersistentStore *persistentStore = [persistentStoreCoordinator addPersistentStoreWithType:NSInMemoryStoreType configuration:nil URL:nil options:nil error:&error]; 
    if (! persistentStore) { 
     NSLog(@"error = %@", error); // TODO: better error handling 
    } 
} 

然後,在保存時選擇文件後面板,臨時持久存儲被遷移到一個SQLite儲存在選定的URL:

- (BOOL)writeToURL:(NSURL *)absoluteURL ofType:(NSString *)typeName forSaveOperation:(NSSaveOperationType)saveOperation originalContentsURL:(NSURL *)absoluteOriginalContentsURL error:(NSError **)error 
{ 
    NSPersistentStoreCoordinator *persistentStoreCoordinator = [self.managedObjectContext persistentStoreCoordinator]; 
    for (NSPersistentStore *persistentStore in [persistentStoreCoordinator persistentStores]) { 
     if (persistentStore.type == NSInMemoryStoreType) { 
      // migrate the in-memory store to a SQLite store 
      NSError *error; 
      NSPersistentStore *newPersistentStore = [persistentStoreCoordinator migratePersistentStore:persistentStore toURL:absoluteURL options:nil withType:NSSQLiteStoreType error:&error]; 
      if (! newPersistentStore) { 
       NSLog(@"error = %@", error); // TODO: better error handling 
      } 
     } 
    } 

    return [super writeToURL:absoluteURL ofType:typeName forSaveOperation:saveOperation originalContentsURL:absoluteOriginalContentsURL error:error]; 
} 
+1

就像你在Mac上一樣,你不能在內存存儲中使用內存,然後在準備好時切換上下文以使用基於文件的存儲?上面的方法也可以解決撤銷問題,因爲如果需要的話,你可以放棄整個上下文堆棧。似乎我在寫這篇文章的時候大家寫的都一樣:) – Jonathan 2011-02-07 19:48:59

回答

5

我是沒有人的核心數據專家,但從我可以從文檔中知道的內容開始,您需要先從內存存儲開始,直到用戶(在他們自己的時間)保存文檔。然後,發送協調者a migratePersistentStore:toURL:options:withType:error: message以從內存中存儲轉換爲新的真正持久存儲。請參閱該文檔以獲取一些重要細節(特別是關於您遷移的商店的命運)。

+0

謝謝彼得!遷移是缺少的難題 - 我已經更新了我的帖子。 – chockenberry 2011-02-07 22:32:46

2

我在工作流程的第一個念頭/保存的部分將是,如果persiste nt store尚未爲文檔創建,以創建臨時內存中存儲,以便導入的數據將保存到該存儲中(儘管文檔/窗口仍將被標記爲髒)。然後,一旦用戶將文檔保存爲真實的文件,您將重新配置協調器以刪除內存中的存儲並將其替換爲磁盤上的存儲,因此所有進一步的保存都將存入磁盤。

0

設置協調器時您是否嘗試過設置臨時文件的URL? 您應該可以在主線程上撤銷-mergeChangesFromContextDidSaveNotification:。無需在後臺線程上爲MOC註冊撤消管理器。

+0

好的解決方案,但是就像Daniel,Peter&Brian說的那樣,簡單地創建一個內存存儲就更簡單了,更不用說更快了。然而,如果我們談論一個非常大的數據集,這將是一個替代方案。 – Jonathan 2011-02-07 19:52:44

2

我不是100%熟悉Mac的東西,但我相信你可以在用戶保存之前使用內存中的持久性存儲,然後在該操作之後添加sql/plist存儲。

可能更好的方法是在標準臨時目錄中創建磁盤上的永久性存儲,並在用戶單擊以保存時將其移動到整個磁盤上。