我有一个辅助托管对象上下文,用于在数据合并回主 moc 之前处理传入的同步数据。不幸的是,我遇到了似乎是合并策略问题的问题。问题不是在将通知合并回主 moc 时发生,而是在此之前......当辅助上下文正在自我保存时。
辅助上下文的合并策略是 NSMergeByPropertyObjectTrumpMergePolicy。如果我删除此策略并让它默认返回典型错误,则此问题不再发生。但是,我试图理解为什么这是一个问题,特别是因为我不想为此上下文使用默认合并策略。
我有一个具有活动属性的用户对象。当同步对象从重新激活用户的服务器进入时,流程如下所示:
在将更改应用于对象之前,这是其初始状态:
(SyncObject *) $29 = 0x0051b6f0 <User: 0x51b6f0> (entity: User; id: 0x526030 <x-coredata://70907366-8102-4131-9230-6F60D0508047/User/p617> ; data: {
active = 0;
...
将更改应用于对象后,正如人们所期望的那样:
(SyncObject *) $30 = 0x0051b6f0 <User: 0x51b6f0> (entity: User; id: 0x526030 <x-coredata://70907366-8102-4131-9230-6F60D0508047/User/p617> ; data: {
active = 1;
...
稍后,在保存之前,我验证了该对象仍然处于活动状态(它是一个 int,因为在这种情况下我直接 po 了内存地址):
(int) $45 = 5355248 <User: 0x51b6f0> (entity: User; id: 0x526030 <x-coredata://70907366-8102-4131-9230-6F60D0508047/User/p617> ; data: {
active = 1;
...
接下来我们进行保存:
[syncContext save:&error];
然后在合并通知块中,我在打印通知时看到了这一点:
updated = "{(\n <User: 0x51b6f0> (entity: User;
id: 0x526030 <x-coredata://70907366-8102-4131-9230-6F60D0508047/User/p617> ;
data: {\n active = 0;\n
...
更糟糕的是,此时的对象如下所示:
(int) $47 = 5355248 <User: 0x51b6f0> (entity: User; id: 0x526030 <x-coredata://70907366-8102-4131-9230-6F60D0508047/User/p617> ; data: {
active = 0;
...
为什么内存中的对象似乎被 SQL 存储中的数据覆盖?据我了解, NSMergeByPropertyObjectTrumpMergePolicy 意味着内存中的不同值将保存在存储中的这些值之上,但显然这不是正在发生的事情。我真的很茫然,这个问题让我很担心,因为它似乎表明来自服务器的更改可能会被丢弃。如果有人知道更多关于这里发生的事情,我很想了解实际发生的事情。
我应该提到,当我删除合并策略时,此保存会引发合并错误,正如我所料,但是我不明白为什么它将我的新更改视为“旧”
(NSError *) $8 = 0x00566720 Error Domain=NSCocoaErrorDomain Code=133020 "The operation couldn’t be completed. (Cocoa error 133020.)" UserInfo=0x591c90 {
conflictList=(
"NSMergeConflict (0x5df220) for NSManagedObject (0xd63a370) with objectID '0xd635310 <x-coredata://70907366-8102-4131-9230-6F60D0508047/User/p617>'
with oldVersion = 9 and newVersion = 10
and old object snapshot = {\n active = 1;\n ...\n}
and new cached row = {\n active = 0;\n ... \n}"
)}
解决方法:
所以在我的情况下,这是因为在主托管对象上下文中对这个特定对象进行了更改。因为我们有一个 Core Data Watcher 类正在运行(监听上下文保存通知),所以我需要在合并新的 MOC 之前保存对该 MOC 的所有更改,以便正确记录用户更改。我是在 mergeChangesFromContextDidSaveNotification 调用之前的 NSManagedObjectContextDidSaveNotification 块中执行此保存,这为时已晚,无法停止冲突。通过将其移动到 NSManagedObjectContextWillSaveNotification 中,mainMOC 将其更改保存到持久存储,观察者注册这些更改,然后辅助存储可以自由尝试将其更改合并到 mainMOC 中,而不必担心与后者可能已经排队的更改发生冲突向上。
作为对此的警告,我必须确保在获取对象以更新传入同步上下文之前,我已保存对主上下文中这些对象的任何未决更改。最终结果证明我在保存对象之前对其进行了快照,因此我在一个上下文中所做的更改与在另一个上下文中准备的更改不同步。虽然我仍然不清楚合并为什么会以这种方式发生,但通过确保在尝试更改对象并将其重新合并之前我拥有对象的最新版本,合并错误消失了,合并过程按需要继续。