核心数据合并两个托管对象上下文
我的 Cocoa/Application 在主线程上有一个托管对象上下文。 当我需要更新数据时,我的程序将:
- 启动一个新线程
- 从服务器接收新数据
- 创建一个新的托管对象上下文
- 向主线程发送通知以合并两个上下文
这是接收通知的函数主线程
- (void)loadManagedObjectFromNotification:(NSNotification *)saveNotification
{
if ([NSThread isMainThread]) {
[self.managedObjectContext mergeChangesFromContextDidSaveNotification:saveNotification];
} else {
[self performSelectorOnMainThread:@selector(loadManagedObjectFromNotification:) withObject:saveNotification waitUntilDone:YES];
}
}
我没有收到任何错误。 我的问题是合并结果,它实际上连接了两个上下文中的托管对象。
我的实体是一个非常简单的属性和关系列表。
也许合并需要一些说明,以便了解更新的托管对象何时不是新的,而是第一个托管对象的编辑版本。 我想象在某个地方我需要指定一种方法来明确标识一个实体(例如,一个属性可以充当 ID)以及类似合并策略的内容(如果 2 个托管对象代表同一个对象,则采用带有最后修改日期的对象)最近的)。
我只需要了解如何正确合并两个上下文,以便为每个对象拥有一个更新的副本。
更新 1
现在问题对我来说很清楚了。 2个上下文有一个很大的区别:ObjectID。 当主线程上的上下文使用持久存储协调器获取 ManagedObjects 时,第二个线程通过获取远程 URL 来创建这些对象。即使对象具有相同的内容,它们也会有 2 个不同的 objectID。
我的对象已经有一个唯一的标识符,我可以使用 setObjectId 来设置该值。 (苹果文档说这不是一个好主意)。
My Cocoa/Application has a Managed Object Context on the main thread.
When I need to update my data my program will:
- Start a new thread
- Receive new data from a server
- Create a new Managed Object Context
- 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).
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
为了正确合并上下文,您需要执行以下操作。
首先,您不需要自己的通知。对上下文执行保存操作会自动将以下通知转发给已注册的观察者:
因此,您需要做的就是:
1) 在您的主线程中,可能在
viewDidLoad
方法中,注册此通知:2) 在主线程中实现
contextDidSave:
方法,如下所示:3) 在
dealloc
方法中添加以下内容:4) 在其他线程中使用以下命令创建新上下文像下面这样的东西方法:
5) 收到新数据后,处理这种情况的正确方法是使用托管对象 ID。由于托管对象 ID 是线程安全的,因此您可以将它们从主线程传递到另一个线程,然后使用
existingObjectWithID:error:
检索与特定 ID 关联的对象,更新它并保存上下文。现在合并将按您的预期进行。或者,如果您事先不知道必须在线程之间传递哪些托管对象 ID,则在另一个线程中,您只需使用谓词来获取对象,以检索与从服务器检索的对象相对应的对象,然后更新它们并保存上下文。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:
Therefore, all you need to do is:
1) in your main thread, may be in the
viewDidLoad
method, register for this notification:2) implement the
contextDidSave:
method in your main thread as follows:3) in your
dealloc
method add the following:4) create a new context in your other thread using something like the following method:
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.