代码之家  ›  专栏  ›  技术社区  ›  John Gallagher

如何在使用nsdistributednotifications的进程之间共享核心数据存储?

  •  8
  • John Gallagher  · 技术社区  · 15 年前

    背景

    我已经发布了一个关于 sharing a Core Data store between processes .

    我正在尝试执行给出的建议,但遇到了一些问题。

    我的目标

    我有两个进程-助手应用程序和用户界面。它们都共享一个数据存储。当助手应用程序将新数据保存到存储时,我希望用户界面更新它的nsmanagedObjectContext。

    当前程序流

    1. Helper应用程序进程将数据写入存储。

    2. 在Helper应用程序中,我监听nsManagedObjectContextDidSaveNotification通知。

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

    4. 我向nsdistributednotificationcenter发送一个nsnotification,使用这个编码的字典作为用户信息。

    5. UI进程正在侦听保存通知。当它收到通知时,它会使用nsonarchiver取消用户信息的归档。

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

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

    8. 我调用MergeChangesFromContextDidSaveNotification:在UI进程的托管对象上下文中,传递在上一步中构造的NSNotification。

    问题

    插入的对象在UI管理的对象上下文fine中出错,它们出现在UI中。更新的对象会出现问题。他们只是不更新。

    我试过什么

    1. 最明显的尝试是 通过保存通知 从Helper应用程序进程到 UI过程。容易,对吧?嗯,不。 分布式通知不会 允许我作为用户信息执行此操作 字典不在右边 格式。所以我才这么做 无存档的东西。

    2. 我试过打电话 刷新对象:合并更改:是打开 要更新的nsmanagedObjects, 但是这个好像没有 效果。

    3. 我试过表演 从ContextDidSaveNotification合并更改: 主线程上的选择器和 当前线程。两者似乎都不是 影响结果。

    4. 我试过用 从ContextDidSaveNotification合并更改: 在线程之间之前,哪一个 课程简单多了,而且很有效 完美。但我也需要这个 流程之间的功能。

    选择?

    我是不是错过了什么?我一直觉得我让它比需要的要复杂得多,但是在阅读了文档几次并花了几天时间之后,我看不到任何其他刷新用户界面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 回复  |  直到 13 年前
        1
  •  1
  •   Ben Lachman    15 年前

    您要查找的是-(void)refreshObject:(nsmanagedObject*)object mergechanges:(bool)我相信的标志。

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

        2
  •  2
  •   Wid    13 年前

    我用这个方法

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

    然后,每个对象都出现了正确的错误,但错误是在缓存中提取的,因此仍然没有更新

    我不得不这样做 [主运行中心失效间隔=0];

    最后,它与关系起了作用。

        3
  •  1
  •   wbyoung    15 年前

    我同意迈克的建议,只是看看商店的文件有没有变化。

    虽然它可能不是最有效的,但我已经成功地使用了 - [NSManagedObjectContext reset] 从第二个流程到商店的变更。在我的例子中,代码是相当线性的——我所做的就是在重置后为一些数据运行一个获取请求。我不知道如何处理绑定和复杂的用户界面,但是如果不能自动处理,您可以发布一个手动更新的通知。

        4
  •  1
  •   nzeltzer    14 年前

    我在iPhone应用程序上也遇到了同样的问题。在我的例子中,解决方案涉及将上下文的不稳定间隔设置为适当的极小值(例如0.5秒)。

        5
  •  1
  •   Arvin Dev    13 年前

    除沙盒应用程序外,此功能正常。不能使用用户信息dict发送通知。请考虑其他一些IPC,如xpc或do。

    另一方面,如果系统繁忙,则使用nsdustributedNotificationCenter并不总是100%。

        6
  •  0
  •   billibala    14 年前

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