This topic has been discussed at many forum, but I am still not able to fully understand how performBlockAndWait
actually works. As per my understanding, cont
Standard messages is old Objective-C lingo. That means you should do all of the regular method calls on a ManagedObjectContext and its child ManagedObjects in the performBlock
or performBlockAndWait
. The only calls that are allowed on a private context outside of the block is init
and setParentContext
. Anything else should be done in a block.
No. Any managed object fetched from a private context must only be accessed on that private context's queue. Accessing (read or write) from another queue is violating the thread confinement rules.
The reason you are having blocking issues is because you have two levels of "mainQueue" contexts and that is "outsmarting" the queue system. This is the flow:
Because of the two levels of main queue contexts it is causing a deadlock where normally the queue system would see the potential deadlock and avoid it.
You can test this by changing your mainContext
variable to:
lazy var mainContext: NSManagedObjectContext = {
let appDelegate = UIApplication.sharedApplication().delegate as? AppDelegate
return appDelegate!.managedObjectContext
}
And your issue goes away because the queue system will see the block and avoid it. You can even see that happening by putting a break point inside of the performBlockAndWait()
and see that you are still on the main queue.
In the end, there is no reason to have two levels of main queue contexts like that in a parent/child design. If anything, this is a good argument NOT to do that.
I missed that you had altered the template code in the appDelegate and turned the overall context into a private one.
That pattern of having a main MOC per vc throws away a lot of the benefits of Core Data. While having a private at the top and a main MOC (that exists for the entire app, not just one VC) is a valid design it won't work if you are doing performBlockAndWait
like this from the main queue.
I would not recommend ever using performBlockAndWait
from the main queue as you are blocking the entire application. performBlockAndWait
should only ever be used when calling TO the main queue (or perhaps one background to another background).