I have two blocks that are being dispatched concurrently on a user-defined concurrent queue, via GCD. At some point in the blocks flow, they have to access the same set of core data managed objects. Not explicitly through a fetch, but rather through an already fetched object which has a to-many relation set.
As far as I understand, the blocks should each have their own context and then, on completion, merge both contexts to the one in the main thread.
However, I’m wondering if a viable alternative to creating 2 contexts and then merging to a third would be to do something like:
- (void)someMethodThatAppliesToAdisjointSetWithRange:(NSRange)range fromSharedObject:(NSManagedObject*)someSharedObject
{
// Do some stuff...
// Create sortDescriptors
__block NSArray* entities = nil;
dispatch_sync(dispatch_get_main_queue(), ^{
entities = [[[someSharedObject valueForKey:@"sprites"] sortedArrayUsingDescriptors:sortDescriptors] retain];
entities = [entities subarrayWithRange:range]
});
for(id anEntity in entities)
{
// STRICTLY retrieve properties from the entities
// And do stuff with these, BUT DON'T modify the entities themselves.
}
// Continue doing stuff that has nothing to do with the managed objects.
}
- (void)dispatchMethod
{
dispatch_async(_concurrentQueue, ^{
[self someMethodThatAppliesToAdisjointSetWithRange:NSMakeRange(0, floor(pageData.count/2.)) fromSharedObject:someSharedObject];
});
dispatch_async(_concurrentQueue, ^{
[self someMethodThatAppliesToAdisjointSetWithRange:NSMakeRange(floor(pageData.count/2.), ceil(pageData.count/2.)) fromSharedObject:someSharedObject];
});
}
My thought on the above is that the dispatches on the main thread create a synchronization point within the concurrent flow, and since I’m not even modifying the managed objects in themselves, it should be fine. However, at some point throughout a whole day of testing, I got
a core data “statement is still active ” inconsistency exception. So now I’m thinking he above code is still not safe. Though the exception might have actually been caused by other code in the app.
Any thoughts?
The empirical answer is NO you cannot. Presumably because any sort of access to relationships in a managedObject will potentially fault and require the context to implicitly fetch the objects in the relationship anyway.
That is,
still requires access to the managedObjectContext.
The same code using two local contexts instead of the suggested approach does not cause the “Statement is still active” exception.