I am using multi-threading to get data, parse it, create objects and store them. And after this is all done, I want the window to be shown.
But now I have 2 issues:
- I have a deadlock
- My barrier does not act as a barrier.
I think the deadlock is because I am updating the managedObjectContext in several threads at once.
-
So I changed my managedObjectContext with the ConcurrencyType:
__managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType]; -
And created an importContext for the concurrency queue and assigned the parentContext:
NSManagedObjectContext *importContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType]; importContext.parentContext = self.managedObjectContext; -
And put my operations in a performBlock for the importContext:
[importContext performBlock:^{ dispatch_async(backgroundQueue, ^{ [myObject methodAWithContext:importContext]; }); dispatch_async(backgroundQueue, ^{ [myObject methodBWithContext:importContext]; }); dispatch_async(backgroundQueue, ^{ [myObject methodCWithContext:importContext]; }); dispatch_barrier_async(backgroundQueueM, ^{ // create barrier to wait for the first 3 threads to be completed. dispatch_async(dispatch_get_main_queue(), ^{ // Save the data from the importContext tot the main context on the main queue NSError *importError = nil; [importContext save:&importError]; [importContext.parentContext performBlock:^{ NSError *parentError = nil; [importContext.parentContext save:&parentError]; }]; [self.window makeKeyAndVisible]; }); }); }];
Approach 1:
In each method, I select a subset of object, delete these and then create new objects and save this.
(I thought the delete was quicker than doing a fetch and check for the existence for every object to be created).
So:
In Method A I select all AObjects, delete them and create new AObjects.
In Method B I select all BObjects, delete them and create new BObjects.
In Method C I select all CObjects, delete them and create new CObjects.
But then I get an error “An NSManagedObjectContext cannot delete objects in other contexts”.
So approach 2:
I removed the delete. But now I get various different errors…..
And the barrier does not wait for the other threads to be executed.
Q1: What am I doing wrong?
Q2: how do I get the barrier to wait for the 3 threads to be completed
Q3: how can I delete / purge objects on various threads?
(I have read the Apple release notes and doc’s, but I can’t find this a clear explanation on the combination for multithreading and managedContext.)
You cannot call
dispatch_asyncwithinperformBlock. A managed object context of typeNSPrivateQueueConcurrencyTypehas it’s own dispatch queue for executing the operations.You try to do several operations in parallel by moving them to a different dispatch queue, but that is not possible.
If you really have to do multiple operations in parallel, you must create a private concurrency type MOC for each operation.
ADDED:
There are several ways to wait for all operations to complete:
performBlock:and check if it’s value is (in your example) 3.dispatch_semaphore_create) for each operation with initial value zero, wait for all the semaphores (dispatch_semaphore_wait) and signal the semaphore at the end of eachperformBlock.BUT: As I re-read your question, I see that you try to delay the
until all Core Data fetch operations have completed. This is not a good design, because the user will see nothing until your data import is done.
A better design is to show an initial view immediately, and update that view when the background operations have fetched data.