核心数据合并两个受管对象上下文 [英] Core Data merge two Managed Object Context

查看:123
本文介绍了核心数据合并两个受管对象上下文的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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


  1. 开始新话题

  2. 从服务器接收新数据

  3. 创建新的托管对象上下文

  4. 向主线程发送通知以合并两个上下文

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

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

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



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

也许合并需要一些指令,以便了解更新的管理对象不是新的管理对象,而是第一个的编辑版本。
我想,在某个地方,我需要指定一种方式来唯一标识一个实体,(一个属性,例如可以像一个ID)和像合并策略(如果2被管对象表示相同的对象,最后一个更新日期更新)。



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



UPDATE 1



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



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

解决方案

这里是你需要做的,上下文。
首先,你不需要自己的通知。对上下文执行保存操作会自动将以下通知转发给注册的观察者:

  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]; code

$ b}



方法添加以下内容:

  [[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必须在线程之间传递,那么在其他线程中,您只需使用谓词检索与从服务器检索的对象相对应的对象,然后更新它们并保存上下文。


My Cocoa/Application has a Managed Object Context on the main thread. When I need to update my data my program will:

  1. Start a new thread
  2. Receive new data from a server
  3. Create a new Managed Object Context
  4. Send a notification to the main thread in order to merge the two context

This is the function that receive the notification on the main thread

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

I do not receive any error. My problem is the merge result, it actually concatenate Managed Objects from both context.

My Entity are a really simple list of attribute and relationship.

Maybe the merge need some instructions in order to understand when an updated Managed Object IS NOT a new one, but a edited version of the first one. I imagine that somewhere I need to specify a way to univocally identify an Entity, (an attribute for example can act like an ID) and something like a merge policy (if 2 managed object represent the same object, take the one with the lastModificationDate more recent).

I just need to understand how to correctly merge the 2 contexts in order to have a single updated copy for each object.

UPDATE 1

The problem is now clear to me. The 2 context has a big difference: the ObjectID. While the context on the main thread fetched the ManagedObjects with the Persistent Store coordinator, the second thread create those object by fetching a remote URL. Even if the objects have the same contents, they will have 2 different objectID.

My objects had already an unique identificator, I could use setObjectId in order to set this value. (Apple documentation says this is NOT a good idea).

解决方案

Here is what you need to do in order to correctly merge the contexts. First, you do not need your own notification. Performing a save operation on a context automatically forwards the following notification to registered observers:

NSManagedObjectContextDidSaveNotification

Therefore, all you need to do is:

1) in your main thread, may be in the viewDidLoad method, register for this notification:

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

2) implement the contextDidSave: method in your main thread as follows:

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

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

}

3) in your dealloc method add the following:

[[NSNotificationCenter defaultCenter] removeObserver:self];

4) create a new context in your other thread using something like the following method:

- (NSManagedObjectContext*)createNewManagedObjectContext
{

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

5) upon receiving the new data, the proper way to handle this situation is the use of managed object IDs. Since managed object IDs are thread safe, you can pass them from your main thread to the other thread, then use existingObjectWithID:error: to retrieve the object associated to a specific ID, update it and save the context. Now the merge will operate as you expect. Alternatively, if you do not know in advance what managed object IDs must be passed between the threads, then in your other thread you simply fetch the objects using a predicate to retrieve the ones corresponding to the objects retrieved from the server, then you update them and save the context.

这篇关于核心数据合并两个受管对象上下文的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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