Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

iOS7 NSMergeConflict on Single Thread Save

Am having problems with a simple data save on a single threaded app after two rows have been re-ordered.

I've managed to simplify the coding to reproduce the error and would appreciate a second opinion with someone else trying this out.

This is a sanity check as I'm suspicious of a core-data issue introduced with iOS 7 as this worked ok in iOS 6.

Firstly, start a new core data project and create this model...

simple core data model

Attribute 'current' is an optional boolean. The one-to-many relationship is an ordered relationship, creating an NSOrderedDataset.

Now add a couple of buttons to the app; the first to create the data (a project and two associated 'drawings') and the second to swap the two drawings, then set a property within the first drawing.

Here's the code...

-(IBAction)onTestButton:(id)sender
{
    id delegate = [[UIApplication sharedApplication]delegate];
    NSManagedObjectContext *managedObjectContext = [delegate managedObjectContext];

    self.project = [NSEntityDescription insertNewObjectForEntityForName:@"Project" inManagedObjectContext:managedObjectContext];
    Drawing *drawing1 = [NSEntityDescription insertNewObjectForEntityForName:@"Drawing" inManagedObjectContext:managedObjectContext];
    Drawing *drawing2 = [NSEntityDescription insertNewObjectForEntityForName:@"Drawing" inManagedObjectContext:managedObjectContext];

    NSMutableOrderedSet* tempSet = [NSMutableOrderedSet orderedSetWithOrderedSet:self.project.drawings];
    [tempSet addObject:drawing1];
    [tempSet addObject:drawing2];
    self.project.drawings = tempSet;

    [self save];
}

-(IBAction)onTestButton2:(id)sender
{
    NSMutableOrderedSet *exchange = [self.project mutableOrderedSetValueForKey:@"drawings"];
    [exchange exchangeObjectAtIndex:0 withObjectAtIndex:1];
    self.project.drawings = exchange;

    [self save];

    Drawing *drawing = [self.project.drawings objectAtIndex:0];

    BOOL current = [drawing.current boolValue];
    drawing.current = [NSNumber numberWithBool:!current];

    [self save];
}

-(void)save
{
    id delegate = [[UIApplication sharedApplication]delegate];
    NSManagedObjectContext *managedObjectContext = [delegate managedObjectContext];
    NSError *error = nil;

    if( ![managedObjectContext save:&error] )
    {
        NSLog(@"%@ Save: Unresolved Error on Save %@", error, [error userInfo] );
        abort();
    }
}

Now, test by pressing the first test button. This sets up the data.

Then press the second test button....all OK!!!

Now press the second test button again and BANG. You 'should get a NSMergeConflict error similar to this....

Save: Unresolved Error on Save { conflictList = ( "NSMergeConflict (0x8a7d0b0) for NSManagedObject (0x8bedfa0) with objectID '0x8bd9340 ' with oldVersion = 1 and newVersion = 2 and old object snapshot = {\n
current = \"\";\n project = \"0x8bc3f50 \";\n} and new cached row = {\n current = \"\";\n project = \"0x8aa88c0 \";\n}" );

I notice from the error that my Project object has changed. However, this is a single thread app using the main app context.

I've spent far too long on this and would appreciate someone else passing comment as to where the issue is. Is this a core-data bug, or am I being a right 'fool'?

Many thanks

/Fitto

like image 915
Fittoburst Avatar asked Oct 29 '13 22:10

Fittoburst


1 Answers

I had similar issues an found a workaround here:

http://prod.lists.apple.com/archives/cocoa-dev/2013/Oct/msg00657.html

In short - add this to your MOC setup:

  [_managedObjectContext setMergePolicy:[[NSMergePolicy alloc] initWithMergeType:NSMergeByPropertyObjectTrumpMergePolicyType]];

This affects OS X 10.9 Mavericks as well when using NSSQLStoreType. I could not repeat the Merge error using NSXMLStoreType.

For Swift 2.x

managedObjectContext.mergePolicy = NSMergePolicy(mergeType: .MergeByPropertyObjectTrumpMergePolicyType)
like image 61
Stefanf Avatar answered Oct 10 '22 02:10

Stefanf