如何使用NSDistributedNotifications在进程之间共享Core Data存储?

时间:2009-11-29 13:17:35

标签: cocoa core-data ipc

背景

我已经发布了一个关于sharing a Core Data store between processes的基础知识的问题。

我正在尝试实施所提出的建议,但我遇到了问题。

我的目标

我有两个流程 - 帮助应用程序和UI。它们共享一个数据存储。当Helper App将新数据保存到商店时,我希望UI更新它的NSManagedObjectContext。

当前的计划流程

  1. Helper App Process将数据写入商店。

  2. 在Helper应用程序中,我侦听NSManagedObjectContextDidSaveNotification通知。

  3. 保存上下文后,我使用URI表示和NSArchiver对插入,删除和更新的对象进行编码。

  4. 我将NSNotification发送到NSDistributedNotificationCenter,并将此编码字典作为userInfo发送。

  5. UI进程正在侦听保存通知。收到通知后,它会使用NSUnarchiver取消归档userInfo。

  6. 它从给定的URI中查找所有更新/插入/删除的对象,并用NSManagedObjects替换它们。

  7. 它使用更新/插入/删除的对象构建NSNotification。

  8. 我在UI流程的托管对象上下文中调用mergeChangesFromContextDidSaveNotification:传入我在上一步中构建的NSNotification。

  9. 问题

    插入的对象出现在UI管理对象上下文中,并且它们出现在UI中。问题来自更新的对象。他们只是不更新​​。

    我尝试了什么

    1. 最明显的尝试就是 是通过保存通知 从Helper App流程到 UI流程。容易,对吗?好吧,不。 分布式通知不会 允许我以userInfo的身份执行此操作 字典不对 格式。这就是为什么我要做所有的事情 NSArchiving的东西。

    2. 我试过打电话 refreshObject:mergeChanges:是的 要更新的NSManagedObjects, 但这似乎没有 效果。

    3. 我试过表演了 mergeChangesFromContextDidSaveNotification: 选择器在主线程和 当前线程。似乎都没有 影响结果。

    4. 我尝试过使用过 mergeChangesFromContextDidSaveNotification: 在线程之间,哪个 当然更简单,也很有效 完美。但我需要同样的东西 流程之间的功能。

    5. 替代吗

      我在这里遗漏了什么吗?我一直觉得我做的比现在要复杂得多,但是经过多次阅读文档并花了几天时间,我看不出任何其他方式来刷新MOC用户界面。

      有更优雅的方式吗?或者我只是在我的代码中某处犯了一个愚蠢的错误?

      守则

      我试图尽可能让它变得可读,但它仍然是一团糟。遗憾。

      帮助应用代码

         -(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];
              }
          }
      

      用户界面代码

      -(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];
      }
      

6 个答案:

答案 0 :(得分:2)

我使用了

中的方法

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

然后每个对象都出现故障但是故障是在缓存中获取的,所以仍然没有更新

我必须这样做 [moc stalenessInterval = 0];

它终于有了合作关系。

答案 1 :(得分:1)

你正在寻找 - (void)refreshObject:(NSManagedObject *)对象mergeChanges:(BOOL)标志我相信。

这将使用持久性存储中的信息刷新对象,并根据需要合并更改。

答案 2 :(得分:1)

我会选择迈克的建议,只是看商店文件的变化。

虽然它可能不是最有效的,但是当商店发生变化时,我在第二个流程中使用- [NSManagedObjectContext reset]成功了。在我的情况下,代码是相当线性的 - 我所做的就是在重置后运行一些数据的获取请求。我不知道这将如何与绑定和复杂的UI一起使用,但如果没有自动处理,您可能会发布通知以手动更新内容。

答案 3 :(得分:1)

我和我一直在研究的iPhone应用程序存在同样的问题。在我的例子中,解决方案涉及将Context的stalenessInterval设置为适当的无穷小(例如,0.5秒)。

答案 4 :(得分:1)

这适用于沙箱应用程序除外。您无法使用用户信息dict发送通知。而是考虑一些其他的IPC,如XPC或DO。

另外,如果系统繁忙,使用NSDustributedNotificationCenter并不总是100%。

答案 5 :(得分:0)

设置托管对象上下文的stalenessInterval有效。我的情况涉及多个线程而不是处理。