iOS7上的NSMergeConflict

时间:2013-10-04 10:25:25

标签: ios objective-c core-data merge

我已更新我的应用以支持iOS 7,并且遇到了问题,即在[context save];的某个屏幕上,我收到以下错误:

NSCocoaErrorDomain Code=133020 "The operation couldn’t be completed. (Cocoa error 133020.)" UserInfo=0x1115a6d0 {conflictList=(
"NSMergeConflict (0x1115a670) for NSManagedObject (0xf25c850) with objectID '0xf25c070 <x-coredata://76AF57C8-F7FF-4880-B06B-63F8B780C96D/Screen/p7>' with oldVersion = 5 and newVersion = 6 
and old object snapshot = {\n    index = 3;\n    message = \"<null>\";\n    status = 0;\n} and new cached row = {\n    index = 3;\n    message = \"<null>\";\n    status = 0;\n}"

在iOS6上,不会出现此问题。

更新: managedObjectContext的代码

-(NSManagedObjectContext *)managedObjectContextForCurrentThread{
if ([NSThread isMainThread])
{
    NSManagedObjectContext *parentContext = self.mainManagedObjectContext.parentContext;
    [parentContext performBlockAndWait:^{
        NSMergePolicy *mergePolicy = [[NSMergePolicy alloc] initWithMergeType:NSMergeByPropertyObjectTrumpMergePolicyType];
        [[self mainManagedObjectContext] setMergePolicy:mergePolicy];
    }];
    return self.mainManagedObjectContext;
}
else
{
    NSMutableDictionary *threadDict = [[NSThread currentThread] threadDictionary];
    NSManagedObjectContext *threadContext = [threadDict objectForKey:kCGMManagedObjectContextKey];
    if (threadContext == nil)
    {
        threadContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
        NSManagedObjectContext *parentContext = self.mainManagedObjectContext.parentContext;
        [parentContext performBlockAndWait:^{
            NSMergePolicy *mergePolicy = [[NSMergePolicy alloc] initWithMergeType:NSMergeByPropertyObjectTrumpMergePolicyType];
            [parentContext setMergePolicy:mergePolicy];
        }];
        [threadContext setParentContext:self.mainManagedObjectContext];
        [threadDict setObject:threadContext forKey:kCGMManagedObjectContextKey];
    }
    return threadContext;
}

}

6 个答案:

答案 0 :(得分:16)

我花了两天时间调试完全相同的错误。你的应用程序和我的应用程序之间的区别在于我只访问主线程中的核心数据,因此合并错误更令人费解。

在我们的例子中,我将其缩小到我们有一个单向关系的事实 - A有很多B(建模为NSSet),但B不知道它A.我们有一个方法修改了A和一个B,当我们去保存这些更改时会导致合并错误。这段代码在iOS 5和iOS上都运行良好很长时间。 6,并且在iOS 7上才开始失败。

确实,添加合并策略会使错误消失,但它也可能会掩盖其他错误。在我们的例子中,我们宁愿看到这些错误而不是冒险有不一致的DB。

将关系更改为双向会导致错误消失。我们的应用程序不需要反向链接,但它们也没有受到伤害。 (幸运的是,改变这种关系作为轻量级迁移正确处理 - 核心数据自动填充在我们的那些反向链接中。)

答案 1 :(得分:15)

根据苹果的文件

NSManagedObjectMergeError = 133020

此错误代码表示合并策略失败 - Core Data无法完成合并。

您的代码中是否有合并政策?请尝试NSMergeByPropertyObjectTrumpMergePolicy。

[self.context setMergePolicy:NSMergeByPropertyObjectTrumpMergePolicy];

答案 2 :(得分:6)

将Xcode 6.3.2与Apple Watchkit扩展一起使用,我在尝试进行多次更新和保存时遇到了同样的错误。 setMergePolicy解决了这个问题,这里是快速代码:

context.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy

确保将上面的行放在context.save命令之前。

答案 3 :(得分:2)

我不想通过设置合并策略来掩盖潜在问题而不首先了解导致NSMergeConflict的原因。

在我的情况下,我之前在代码中执行了NSBatchDeleteRequestNSBatchDeleteRequest直接在持久性存储协调器上执行,因此ManagedObjectContext不知道删除并仍然保留对已删除对象的引用。当我稍后引用其中一个对象并尝试保存上下文时,NSMergeConflict被抛出。

执行删除后,在reset()上呼叫moc修复了问题。

let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "Tasks")
let batchDeleteRequest = NSBatchDeleteRequest(fetchRequest: fetchRequest)
try managedContext.execute(batchDeleteRequest)
managedContext.reset() 

答案 4 :(得分:1)

我得到了类似的错误,在我的情况下,锁定NSPersistentStoreCoordinator工作。

[context.persistentStoreCoordinator lock];
[context performBlockAndWait:^{
   // do something
}];
[context.persistentStoreCoordinator unlock]

我不知道它为什么会起作用,但我怀疑是NSManagedObjectContext的错误。 我希望这会有所帮助。

答案 5 :(得分:0)

我在使用完整存储进行测试时得到了这个。因此,似乎任何类型的合并失败(在我的情况下,存储已满并且持久存储无法更新)将生成此。