Run BlockAndWait creates a dead end

I am writing a function that does some CoreData stuff. I want the function to return only after all CoreData operations have been completed. CoreData stuff involves creating an object in the background context, and then performing some additional actions in the parent context:

+ (void) myFunction NSManagedObjectContext *backgroundContext = [DatabaseDelegate sharedDelegate].backgroundContext; [backgroundContext performBlockAndWait:^{ MyObject *bla = create_my_object_in:backgroundContext; [backgroundContext obtainPermanentIDsForObjects:[[backgroundContext insertedObjects] allObjects] error:nil]; [backgroundContext save:nil]; [[DatabaseDelegate sharedDelegate].parent.managedObjectContext performBlockAndWait:^{ [[DatabaseDelegate sharedDelegate].parent updateChangeCount:UIDocumentChangeDone]; // Do some more stuff NSOperationQueue *queue = [[NSOperationQueue alloc] init]; [queue addOperation:someOperation]; }]; }]; return; } 

I want the return to happen only after [queue addOperation:someOperation] . This seems to work in most cases, but I had one case where this function never returned. He seemed to be at a standstill, and I suspect that this is due to performBlockAndWait .

My questions:

(1) Can someone explain why this dead end occurs?

and

(2) What is the correct way to achieve the same functionality? The requirement is that myFunction returned only after both blocks have been executed.

Thanks!

+4
ios objective-c deadlock core-data nsmanagedobjectcontext
source share
2 answers

Suppose you call myFunction from the main thread. Assume that [DatabaseDelegate sharedDelegate].parent.managedObjectContext scheduled on the main thread.

With [backgroundContext performBlockAndWait:] you plan to block in a private private context queue. Blocking the main thread.

With [.parent.managedObjectContext performBlockAndWait:] you plan to block in the main thread, blocking the private queue.

But the main thread is already blocked. Thus, the block will never be executed. And performBlockAndWait: will never return.

Dead end.

Use asynchronously scheduled blocks with termination blocks.

+10
source share

You do not have to wait. Your background work is done, and then before it is done , it will start working on the main thread, and before it is done, it will do your "someOperation". You can replace it with asynchronous one and it will work anyway.

Looking at this code, there is no reason to use blocking versions ...

 + (void) myFunction { NSManagedObjectContext *backgroundContext = [DatabaseDelegate sharedDelegate].backgroundContext; [backgroundContext performBlock:^{ // Asynchronous... but every command in this block will run before this // block returns... MyObject *bla = create_my_object_in:backgroundContext; [backgroundContext obtainPermanentIDsForObjects:[[backgroundContext insertedObjects] allObjects] error:nil]; [backgroundContext save:nil]; [[DatabaseDelegate sharedDelegate].parent.managedObjectContext performBlock:^{ // Asynchronous, but this whole block will execute... [[DatabaseDelegate sharedDelegate].parent updateChangeCount:UIDocumentChangeDone]; // Do some more stuff // This will not run until after the stuff above in this block runs... NSOperationQueue *queue = [[NSOperationQueue alloc] init]; [queue addOperation:someOperation]; }]; // You will reach here BEFORE the code in the previous block executes, but // the "someOperation" is in that block, so it will not run until that // block is done. }]; // Likewise, you will reach here before the above work is done, but everything // will still happen in the right order relative to each other. return; } 
+2
source share

All Articles