【问题标题】:How do I share a Core Data store between processes using NSDistributedNotifications?如何使用 NSDistributedNotifications 在进程之间共享核心数据存储?
【发布时间】:2010-12-21 09:25:50
【问题描述】:

背景

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

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

我的目标

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

当前程序流程

  1. Helper App Process 将数据写入 Store。

  2. 在 Helper App 中,我监听 NSManagedObjectContextDidSaveNotification 通知。

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

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

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

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

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

  8. 我在UI Process的Managed Object Context上调用mergeChangesFromContextDidSaveNotification:,传入我在上一步构建的NSNotification。

问题

插入的对象在 UI Managed Object Context 中出现故障并出现在 UI 中。问题来自更新的对象。他们只是不更新​​。

我的尝试

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

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

  3. 我已尝试执行 mergeChangesFromContextDidSaveNotification: 主线程上的选择器和 当前线程。似乎都没有 影响结果。

  4. 我试过用 mergeChangesFromContextDidSaveNotification: 在线程之间之前,哪个 课程要简单得多,而且有效 完美。但我也需要这个 进程之间的功能。

替代方案?

我在这里遗漏了什么吗?我一直觉得我做的比它需要的复杂得多,但是在阅读了几次文档并在这上面花了几天时间之后,我看不到任何其他刷新 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];
}

【问题讨论】:

  • 您是否有理由尝试使用进程间通信而不是查看持久存储文件本身以查看它何时更新?
  • 并非如此。但是,如果我查看了存储文件,我需要有一些方法来刷新托管对象上下文,而我能找到的唯一方法是使用 mergeChangesFromContextDidSaveNotification: 方法。我怀疑我错过了一种非常明显的刷新 MOC 的方法,而不依赖于这种方法。
  • for(id thisSavedObject in [thisSavedObjectSet allObjects]) 可以写成for(id thisSavedObject in thisSavedObjectSet)
  • 是的,好点。早在 11 月 9 日那个令人兴奋的日子里,我没有意识到快速枚举也适用于集合。

标签: cocoa core-data ipc


【解决方案1】:

这有效,沙盒应用除外。您不能使用用户信息字典发送通知。请考虑使用其他 IPC,例如 XPC 或 DO。

附带说明,如果系统繁忙,使用 NSDustributedNotificationCenter 并不总是 100%。

【讨论】:

    【解决方案2】:

    我用的方法

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

    那么每个对象都是正确的错误,但是错误是在缓存中获取的,所以仍然没有更新

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

    它终于奏效了,有了关系。

    【讨论】:

    • 设置 stalenessInterval 为我做了。谢谢!
    【解决方案3】:

    设置托管对象上下文的 stalenessInterval 有效。我的案例涉及多个线程而不是进程。

    【讨论】:

      【解决方案4】:

      我一直在开发的 iPhone 应用程序也遇到了同样的问题。就我而言,解决方案涉及将 Context 的 stalenessInterval 设置为适当的无穷小(例如 0.5 秒)。

      【讨论】:

        【解决方案5】:

        我会听从 Mike 的建议,只是观察商店文件的变化。

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

        【讨论】:

          【解决方案6】:

          您正在寻找 - (void)refreshObject:(NSManagedObject *)object mergeChanges:(BOOL)flag 我相信。

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

          【讨论】:

          • 我在我的代码中使用了这个。但是,以我使用它的方式,它似乎不起作用。
          猜你喜欢
          • 1970-01-01
          • 2010-12-14
          • 1970-01-01
          • 2019-11-08
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-01-11
          • 1970-01-01
          相关资源
          最近更新 更多