2009-11-29 26 views
8

背景如何在使用NSDistributedNotifications的進程之間共享Core Data存儲?

我已經發布了關於sharing a Core Data store between processes基本問題。

我試圖執行給出的建議,我遇到了問題。

我的目標

我有兩個進程 - 的助手應用程序和用戶界面。他們都共享一個數據存儲。當輔助應用程序將新數據保存到商店時,我希望UI更新它的NSManagedObjectContext。

當前程序流

  1. 的助手應用程序過程將數據寫入存儲。

  2. 在助手應用程序中,我偵聽NSManagedObjectContextDidSaveNotification通知。

  3. 保存上下文時,我使用它們的URI表示和NSArchiver對插入,刪除和更新的對象進行編碼。

  4. 我發送一個NSNotification到NSDistributedNotificationCenter並將此編碼字典作爲userInfo。

  5. UI進程正在偵聽保存通知。當它收到通知時,它使用NSUnarchiver解除對userInfo的存檔。

  6. 它從給出的URI中查找所有更新/插入/刪除的對象,並用NSManagedObjects替換它們。

  7. 它使用更新/插入/刪除的對象構造NSNotification。

  8. 我調用mergeChangesFromContextDidSaveNotification:在UI進程的託管對象上下文中傳入我在上一步中構造的NSNotification。

的問題

插入的對象是有故障的入UI管理對象上下文精細和它們出現在UI。問題伴隨更新的對象。他們只是不更新​​。

我已經試過

  1. 最明顯的事情,試圖將 是通過從助手應用程序過程中的保存通知 到 UI過程。很簡單,對吧?那麼,不。 分佈式通知不會 允許我這樣做,因爲userInfo 字典不是正確的 格式。這就是爲什麼我正在做所有的NSArchiving的東西。

  2. 我已經打過電話 refreshObject:mergeChanges:是對 的NSManagedObjects更新, 但這似乎並沒有什麼效果 。

  3. 我已經試過執行 mergeChangesFromContextDidSaveNotification:在主線程 選擇和 當前線程。似乎 影響結果。

  4. 我使用 mergeChangesFromContextDidSaveNotification嘗試: 之前線程之間,其中 當然要簡單得多,它完美地工作 。但是我需要在進程之間提供相同的功能 。

替代品?

我在這裏錯過了什麼嗎?我一直都覺得自己做得比想要的要複雜得多,但是在多次閱讀文檔並花了幾天時間之後,我看不到任何其他方式來刷新MOC UI。

有沒有更好的方法來做到這一點?或者我在代碼中的某個地方犯了一個愚蠢的錯誤?

守則

我試圖使它儘可能地易讀,但它仍然是一個爛攤子。抱歉。

助手應用程序代碼

-(void)workerThreadObjectContextDidSave:(NSNotification *)saveNotification { 
     NSMutableDictionary *savedObjectsEncodedURIs = [NSMutableDictionary dictionary]; 
     NSArray *savedObjectKeys = [[saveNotification userInfo] allKeys]; 

     for(NSString *thisSavedObjectKey in savedObjectKeys) { 
      // This is the set of updated/inserted/deleted NSManagedObjects. 
      NSSet *thisSavedObjectSet = [[saveNotification userInfo] objectForKey:thisSavedObjectKey]; 
      NSMutableSet *thisSavedObjectSetEncoded = [NSMutableSet set]; 

      for(id thisSavedObject in [thisSavedObjectSet allObjects]) { 
       // Construct a set of URIs that will be encoded as NSData 
       NSURL *thisSavedObjectURI = [[(NSManagedObject *)thisSavedObject objectID] URIRepresentation]; 
       [thisSavedObjectSetEncoded addObject:thisSavedObjectURI]; 
      } 
      // Archive the set of URIs. 
      [savedObjectsEncodedURIs setObject:[NSArchiver archivedDataWithRootObject:thisSavedObjectSetEncoded] forKey:thisSavedObjectKey]; 
     } 

     if ([[savedObjectsEncodedURIs allValues] count] > 0) { 
      // Tell UI process there are new objects that need merging into it's MOC 
      [[NSDistributedNotificationCenter defaultCenter] postNotificationName:@"com.synapticmishap.lapsus.save" object:@"HelperApp" userInfo:(NSDictionary *)savedObjectsEncodedURIs]; 
     } 
    } 

UI代碼

-(void)mergeSavesIntoMOC:(NSNotification *)notification { 
    NSDictionary  *objectsToRefresh  = [notification userInfo]; 
    NSMutableDictionary *notificationUserInfo = [NSMutableDictionary dictionary]; 
    NSArray *savedObjectKeys = [[notification userInfo] allKeys]; 

    for(NSString *thisSavedObjectKey in savedObjectKeys) { 
     // Iterate through all the URIs in the decoded set. For each URI, get the NSManagedObject and add it to a set. 
     NSSet *thisSavedObjectSetDecoded = [NSUnarchiver unarchiveObjectWithData:[[notification userInfo] objectForKey:thisSavedObjectKey]]; 
     NSMutableSet *savedManagedObjectSet = [NSMutableSet set]; 

     for(NSURL *thisSavedObjectURI in thisSavedObjectSetDecoded) { 
      NSManagedObject *thisSavedManagedObject = [managedObjectContext objectWithID:[persistentStoreCoordinator managedObjectIDForURIRepresentation:thisSavedObjectURI]]; 
      [savedManagedObjectSet addObject:thisSavedManagedObject]; 
      // If the object is to be updated, refresh the object and merge in changes. 
      // This doesn't work! 
      if ([thisSavedObjectKey isEqualToString:NSUpdatedObjectsKey]) { 
       [managedObjectContext refreshObject:thisSavedManagedObject mergeChanges:YES]; 
       [managedObjectContext save:nil]; 
      } 
     } 
     [notificationUserInfo setObject:savedManagedObjectSet forKey:thisSavedObjectKey]; 
    } 
    // Build a notification suitable for merging changes into MOC. 
    NSNotification *saveNotification = [NSNotification notificationWithName:@"" object:nil userInfo:(NSDictionary *)notificationUserInfo]; 
    [managedObjectContext performSelectorOnMainThread:@selector(mergeChangesFromContextDidSaveNotification:) 
            withObject:saveNotification 
           waitUntilDone:YES]; 
} 
+1

是否有一個原因,你試圖使用進程間通信,而不是看持久存儲文件本身來查看它何時更新? –

+0

不是。但是,如果我看了商店文件,我需要刷新Managed Object Context的一些方法,我可以通過mergeChangesFromContextDidSaveNotification:方法找到執行此操作的唯一方法。我懷疑我錯過了一個非常明顯的刷新MOC而不依賴這種方法的方式。 –

+0

'for(id thisSavedObject in [thisSavedObjectSet allObjects])''可以寫成for(id thisSavedObject in thisSavedObjectSet)' – user102008

回答

1

你要找的 - (空)refreshObject:(NSManagedObject *)對象mergeChanges:(BOOL)標誌我相信。

這將刷新對象與持久性存儲的信息,合併的變化,如果你想要的。

+0

我在我的代碼中使用了這個。但是,在我使用它的方式中,它似乎不起作用。 –

1

我願意和邁克的建議一起去看商店文件的變化。

雖然它可能不是最有效的,我已經使用- [NSManagedObjectContext reset]從第二過程時,有一個變化到商店取得了成功。在我的情況下,代碼是相當線性的—我所做的是在重置後爲某些數據運行提取請求。我不知道這將如何處理綁定和複雜的用戶界面,但是如果不自動處理,您可能會發布通知以手動更新。

1

我有一個iPhone應用程序,我一直在努力完全相同的問題。就我而言,解決方案涉及將Context的陳舊間隔設置爲適當的無限小(例如0.5秒)。

0

設置管理對象上下文的陳舊度間隔工作。雖然我的情況涉及多個線程而不是流程。

2

我所使用的方法在

http://www.mlsite.net/blog/?p=518

然後每個對象被正確地故障,但故障在緩存中,以便仍然取無更新

我不得不做 [MOC stalenessInterval = 0] ;

它終於有了關係。

+0

設置陳舊間隔爲我做了。謝謝! – MrMage

1

這個工程,除了沙箱應用程序。您無法使用用戶信息字典發送通知。而應考慮其他一些IPC,如XPC或DO。

在旁註中,如果系統繁忙,則使用NSDustributedNotificationCenter並不總是100%。