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

时间:2011-08-05 16:03:06

标签: objective-c cocoa core-data nsmanagedobject nsmanagedobjectcontext

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

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

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

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

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

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

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

    更新1

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

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

1 个答案:

答案 0 :(得分:33)

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

NSManagedObjectContextDidSaveNotification

因此,您需要做的就是:

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

[[NSNotificationCenter defaultCenter] addObserver:self
                                         selector:@selector(contextDidSave:)
                                             name:NSManagedObjectContextDidSaveNotification
                                            object:nil];

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

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

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

}

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

[[NSNotificationCenter defaultCenter] removeObserver:self];

4)使用类似以下方法的东西在你的其他线程中创建一个新的上下文:

- (NSManagedObjectContext*)createNewManagedObjectContext
{

    NSManagedObjectContext *moc = [[NSManagedObjectContext alloc] init]; 
    [moc setPersistentStoreCoordinator:[self persistentStoreCoordinator]];
    [moc setUndoManager:nil];
    return [moc autorelease];
}

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