如何使用NSDistributedNotifications在进程之间共享Core Data存储? [英] How do I share a Core Data store between processes using NSDistributedNotifications?

查看:211
本文介绍了如何使用NSDistributedNotifications在进程之间共享Core Data存储?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

背景



我已经发布了有关


$

b $ b

我试图实现给出的建议,我遇到了问题。



我的目标 >

我有两个进程 - 助手应用程序和UI。它们都共享单个数据存储。



当前程序流程

$帮助应用程序已将新数据保存到商店。 b
$ b


  1. 助手应用程序将数据写入商店。


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


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


  4. 我向NSDistributedNotificationCenter发送NSNotification,此编码字典为userInfo。


  5. UI进程正在监听保存通知。


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


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


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


问题



插入的对象被错误插入到UI管理对象上下文中,它们显示在UI中。问题是更新的对象。他们只是不更新​​。



我尝试过的


  1. 最明显的尝试是
    将保存通知
    从帮助应用程序进程传递到
    UI进程。容易,对吧?好吧,没有。
    分布式通知不会
    允许我这样做,因为userInfo
    字典不是正确的
    格式。这是为什么我做所有的
    NSArchiving的东西。


  2. 我试过调用
    refreshObject:mergeChanges:YES on
    NSManagedObjects要更新,
    ,但这似乎没有任何
    效果。



  3. mergeChangesFromContextDidSaveNotification:
    选择器在主线程和
    当前线程。


  4. 我试过在线程之间使用
    mergeChangesFromContextDidSaveNotification:

    课程更简单,它完美地工作
    。但是我需要在流程之间使用相同的
    功能。


/ p>

我缺少这里的东西吗?我一直得到的感觉,我做的这更复杂,因为它需要是,但阅读文档几次,并花了几天坚持这一点,我看不到任何其他方式刷新MOC



有更优雅的方法吗?



p>我试图使它尽可能可读,但它仍然是一团糟。对不起。



帮助程序代码

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

for(NSString * thisSavedObjectKey in savedObjectKeys){
//这是更新/插入/删除NSManagedObjects的集合。
NSSet * thisSavedObjectSet = [[saveNotification userInfo] objectForKey:thisSavedObjectKey];
NSMutableSet * thisSavedObjectSetEncoded = [NSMutableSet set];

for(id thisSavedObject in [thisSavedObjectSet allObjects]){
//构造一组将被编码为NSData的URI
NSURL * thisSavedObjectURI = [[(NSManagedObject *) thisSavedObject objectID] URIRepresentation];
[thisSavedObjectSetEncoded addObject:thisSavedObjectURI];
}
//存档URI集合。
[savedObjectsEncodedURIs setObject:[NSArchiver archivedDataWithRootObject:thisSavedObjectSetEncoded] forKey:thisSavedObjectKey];
}

if([[savedObjectsEncodedURIs allValues] count]> 0){
//告诉UI进程有新对象需要合并到它的MOC
[NSDistributedNotificationCenter defaultCenter] postNotificationName:@com.synapticmishap.lapsus.saveobject:@HelperAppuserInfo:(NSDictionary *)savedObjectsEncodedURIs];
}
}

UI代码 p>

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

for(NSString * thisSavedObjectKey in savedObjectKeys){
//迭代解码集中的所有URI。对于每个URI,获取NSManagedObject并将其添加到集合。
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([thisSavedObjectKey isEqualToString:NSUpdatedObjectsKey]){
[managedObjectContext refreshObject:thisSavedManagedObject mergeChanges:YES];
[managedObjectContext save:nil];
}
}
[notificationUserInfo setObject:savedManagedObjectSet forKey:thisSavedObjectKey];
}
//构建适合于将更改合并到MOC中的通知。
NSNotification * saveNotification = [NSNotification notificationWithName:@object:nil userInfo:(NSDictionary *)notificationUserInfo];
[managedObjectContext performSelectorOnMainThread:@selector(mergeChangesFromContextDidSaveNotification :)
withObject:saveNotification
waitUntilDone:YES];
}


解决方案

(void)refreshObject:(NSManagedObject *)object mergeChanges:(BOOL)flag我相信。



这将刷新持久存储中的信息对象,合并更改if你想要的。


Background

I've already posted a question about the basics of sharing a Core Data store between processes.

I'm trying to implement the recommendations given and I'm running into problems.

My Goal

I have two processes - the Helper App and the UI. They both share a single data store. I want the UI to update it's NSManagedObjectContext when the Helper App has saved new data to the store.

Current Program Flow

  1. The Helper App Process writes data to the Store.

  2. In the Helper App, I listen for NSManagedObjectContextDidSaveNotification notifications.

  3. When the context is saved, I encode the inserted, deleted and updated objects using their URI representations and NSArchiver.

  4. I send an NSNotification to the NSDistributedNotificationCenter with this encoded dictionary as the userInfo.

  5. The UI Process is listening for the save notification. When it receives the notification, it unarchives the userInfo using NSUnarchiver.

  6. It looks up all the updated/inserted/deleted objects from the URIs given and replaces them with NSManagedObjects.

  7. It constructs an NSNotification with the updated/inserted/deleted objects.

  8. I call mergeChangesFromContextDidSaveNotification: on the Managed Object Context of the UI Process, passing in the NSNotification I constructed in the previous step.

The Problem

Inserted objects are faulted into the UI Managed Object Context fine and they appear in the UI. The problem comes with updated objects. They just don't update.

What I've tried

  1. The most obvious thing to try would be to pass the save Notification from the Helper App process to the UI process. Easy, right? Well, no. Distributed Notifications won't allow me to do that as the userInfo dictionary is not in the right format. That's why I'm doing all the NSArchiving stuff.

  2. I've tried calling refreshObject:mergeChanges:YES on the NSManagedObjects to be updated, but this doesn't seem to have any effect.

  3. I've tried performing the mergeChangesFromContextDidSaveNotification: selector on the main thread and the current thread. Neither seems to affect the result.

  4. I've tried using mergeChangesFromContextDidSaveNotification: before between threads, which of course is much simpler and it worked perfectly. But I need this same functionality between processes.

Alternatives?

Am I missing something here? I'm consistently getting the feeling I'm making this much more complex than it needs to be, but after reading the documentation several times and spending a few solid days on this, I can't see any other way of refreshing the MOC of the UI.

Is there a more elegant way of doing this? Or am I just making a silly mistake somewhere in my code?

The Code

I've tried to make it as readable as possible, but it's still a mess. Sorry.

Helper App Code

   -(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 Code

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

解决方案

You're looking for - (void)refreshObject:(NSManagedObject *)object mergeChanges:(BOOL)flag I believe.

This will refresh the object with the info in the persistent store, merging changes if you want.

这篇关于如何使用NSDistributedNotifications在进程之间共享Core Data存储?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆