Sam
Sam

Reputation: 3485

Does core data consider a value as changed if it is set to the same value it was?

For the purpose of ensuring I have chosen the correct NSMergePolicy I am curious as to whether a value being set to its current value is capable of causing a merge conflict across multiple contexts.

Specifically, in my case I want to ensure that a modified flag will conflict and be preserved if set at an inopportune moment.

Example:

//...
//on background thread, doing some work to an object because it's status was
//set to Status_Modified
[managedObjectContext  performBlockAndWait:^{
    object.status = Status_NotModified;
    [managedObjectContext setMergePolicy:NSMergeByPropertyStoreTrumpMergePolicy];
    [managedObjectContext save:&error];
}];

What if while this is going on, on the main thread, the status is set to Status_Modified and saved? Will the objects status stay as Status_Modified? I.e. will the 'status' property be considered to be changed and so cause a conflict and therefore trump our in memory change (according to the policy)?

Upvotes: 0

Views: 70

Answers (1)

Sam
Sam

Reputation: 3485

So, I cannot find any decent documentation to answer this question, but I have done some tests and it seems that the property is considered to be changed. This was my suspicion and seems to agree with various references to key-value setting being wrapped by will/didSetValueForKey:

My test:

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    NSManagedObjectContext * uiCtx = [self contextForUIWork];
    NSEntityDescription * entityDesc = [NSEntityDescription entityForName:@"Entity" inManagedObjectContext:uiCtx];
    Entity * entity = [[Entity alloc] initWithEntity:entityDesc insertIntoManagedObjectContext:uiCtx];
    entity.testproperty = @(1);
    NSError * error = nil;
    [uiCtx save:&error];
    if (error)
    {
        assert(0);
    }

    NSManagedObjectID * objID = entity.objectID;
    [self doStuffToObjectWithIDOnAnotherThreadAndAnotherContext:objID];
    entity.testproperty = @(2);
    [uiCtx setMergePolicy:NSErrorMergePolicy];
    error = nil;
    [uiCtx save:&error];
    if (!error)
    {
        //We do not hit this! Success!
        assert(0);
    }
}

-(void)doStuffToObjectWithIDOnAnotherThreadAndAnotherContext:(NSManagedObjectID*)objID
{
    dispatch_barrier_sync(dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0), ^{
        NSManagedObjectContext * bgCtx = [self contextForBackgroundWork];
        Entity * bgEntity = (Entity*)[bgCtx objectWithID:objID];

        [bgCtx performBlockAndWait:^{

            //set to same value
            bgEntity.testproperty = bgEntity.testproperty;

            NSError * bgError = nil;
            [bgCtx save:&bgError];
            if (bgError)
            {
                assert(0);
            }
        }];
    });
}

(Full test code uploaded here: https://github.com/samskiter/CoreDataValueChangingTest )

A citation from the docs confirming this would be far better than just some test that shows it works on this particular version of iOS.

Upvotes: 2

Related Questions