Ios – NSMergeConflict on iOS7

core-dataiosmergeobjective c

I have updated my app to support iOS 7 and have been faced with the problem that on one of screens in my [context save]; I get the following error:

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}"

On iOS6 this problem does not occur.

Update:
Code for 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;
}

}

Best Answer

I just spent two days debugging the exact same error. The difference between your app and mine is that mine only accesses core data from the main thread, so the merge error was even more puzzling.

In our case I narrowed it down to the fact that we had a unidirectional relationship - A has many Bs (modeled as an NSSet), but B doesn't know its A. We had a method that modified both an A and a B, and would cause a merge error when we went to save those changes. This code worked fine for a long time on both iOS 5 & 6, and only started to fail on iOS 7.

It's true that adding a merge policy will make the error go away, but it might also mask other errors. In our case we'd rather see those errors than risk having an inconsistent DB.

Changing the relationship to bidirectional made the error go away. The back links aren't necessary for our app, but they aren't hurting either. (And happily, changing this relationship was handled correctly as a lightweight migration - core data automatically filled in those back links for us.)