NSManagedObjectContext and executeBlock, changes in iOS 8?
I have an old project (running on iOS 7) with this simple code:
in AppDelegate I create managedObjectContext:
- (NSManagedObjectContext *)managedObjectContext {
// Returns the managed object context for the application (which is already bound to the persistent store coordinator for the application.)
if (_managedObjectContext != nil) {
return _managedObjectContext;
}
NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
if (!coordinator) {
return nil;
}
_managedObjectContext = [[NSManagedObjectContext alloc] init];
[_managedObjectContext setPersistentStoreCoordinator:coordinator];
return _managedObjectContext;
}
Then I perform an update operation in the view controller:
[context performBlock:^{
[context deleteObject:anObject];
NSError *error = nil;
if (![context save:&error])
{
NSLog(@"Error saving context");
}
}];
I'm sure this code worked correctly on iOS 7.0, but it fails when called performBlock:
on iOS 8 with this error:
Can only use -performBlockAndWait: on the NSManagedObjectContext that was created with the queue.
I can resolve the error by changing the init method of the NSManagedObjectContext instance as follows:
_managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
But I don't understand why this behavior changed. In the NSManagedObjectContext documentation, you can read:
The consequence of this is that the context assumes that the default owner is the thread or queue that allocates it - this is determined by the thread that calls its init method.
So in my first example, using a simple call init
, the owner of the context queue is the main thread. The call performBlock:
was made on the main thread as well, so I don't understand why this error. Am I missing something or is this a bug in iOS 8?
source to share
The call -[NSManagedObjectContext init]
is just a wrapper around -[NSManagedObjectContext initWithConcurrencyType:]
with an argument NSConfinementConcurrencyType
. This will create an instance NSManagedObjectContext
that uses the legacy content constraint model that doesn't use a queue. Contexts created using init
or initWithConcurrencyType:
with a passed value NSConfinementConcurrencyType
are incompatible with the methods of the queue performBlock:
or performBlockAndWait:
.
Build your context with -[NSManagedObjectContext initWithConcurrencyType:]
and swipe either NSPrivateQueueConcurrencyType
or NSMainQueueConcurrencyType
if needed. The resulting context is compatible with performBlock:
and performBlockAndWait:
will use the queue constraint model that was introduced in iOS 5.
source to share