核心数据合并两个托管对象上下文

Giu*_*ppe 22 cocoa core-data objective-c nsmanagedobject nsmanagedobjectcontext

我的Cocoa/Application在主线程上有一个托管对象上下文.当我需要更新我的数据时,我的程序将:

  1. 开始一个新的主题
  2. 从服务器接收新数据
  3. 创建新的托管对象上下文
  4. 向主线程发送通知以合并两个上下文

这是在主线程上接收通知的函数

- (void)loadManagedObjectFromNotification:(NSNotification *)saveNotification
{
    if ([NSThread isMainThread]) {
        [self.managedObjectContext mergeChangesFromContextDidSaveNotification:saveNotification];
    } else {
        [self performSelectorOnMainThread:@selector(loadManagedObjectFromNotification:) withObject:saveNotification waitUntilDone:YES];     
    }
}
Run Code Online (Sandbox Code Playgroud)

我没有收到任何错误.我的问题是合并结果,它实际上连接了两个上下文中的Managed Objects.

我的实体是一个非常简单的属性和关系列表.

也许合并需要一些指令,以便了解更新的托管对象何时不是新的,而是第一个的编辑版本.我想在某个地方我需要指定一种方式来单义地识别实体,(例如,属性可以像ID一样)和类似合并策略的东西(如果2个被管理对象代表同一个对象,请使用lastModificationDate更多)最近).

我只需要了解如何正确合并2个上下文,以便为每个对象创建一个更新的副本.

更新1

这个问题现在对我来说很清楚了.2上下文有很大的不同:ObjectID.当主线程上的上下文使用持久存储协调器获取ManagedObjects时,第二个线程通过获取远程URL来创建这些对象.即使对象具有相同的内容,它们也将具有2个不同的objectID.

我的对象已经有一个唯一的标识符,我可以使用setObjectId来设置这个值.(Apple文档说这不是一个好主意).

Mas*_*aro 33

为了正确合并上下文,您需要执行以下操作.首先,您不需要自己的通知.对上下文执行保存操作会自动将以下通知转发给已注册的观察者:

NSManagedObjectContextDidSaveNotification
Run Code Online (Sandbox Code Playgroud)

因此,您需要做的就是:

1)在你的主线程中,可能在viewDidLoad方法中,注册此通知:

[[NSNotificationCenter defaultCenter] addObserver:self
                                         selector:@selector(contextDidSave:)
                                             name:NSManagedObjectContextDidSaveNotification
                                            object:nil];
Run Code Online (Sandbox Code Playgroud)

2)contextDidSave:在主线程中实现方法如下:

- (void)contextDidSave:(NSNotification *)notification
{

    SEL selector = @selector(mergeChangesFromContextDidSaveNotification:); 
    [managedObjectContext performSelectorOnMainThread:selector withObject:notification waitUntilDone:YES];

}
Run Code Online (Sandbox Code Playgroud)

3)在你的dealloc方法中添加以下内容:

[[NSNotificationCenter defaultCenter] removeObserver:self];
Run Code Online (Sandbox Code Playgroud)

4)使用类似以下方法的方法在您的其他线程中创建新上下文:

- (NSManagedObjectContext*)createNewManagedObjectContext
{

    NSManagedObjectContext *moc = [[NSManagedObjectContext alloc] init]; 
    [moc setPersistentStoreCoordinator:[self persistentStoreCoordinator]];
    [moc setUndoManager:nil];
    return [moc autorelease];
}
Run Code Online (Sandbox Code Playgroud)

5)在接收到新数据时,处理这种情况的正确方法是使用管理对象ID.由于托管对象ID是线程安全的,因此您可以将它们从主线程传递到另一个线程,然后用于existingObjectWithID:error:检索与特定ID关联的对象,更新它并保存上下文.现在合并将按预期运行.或者,如果您事先不知道哪些托管对象ID必须在线程之间传递,那么在您的另一个线程中,您只需使用谓词获取对象以检索与从服务器检索的对象相对应的对象,然后更新它们并保存上下文.