Reputation: 3485
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
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