Master data: parent context blocks child elements

I am doing some background processing in an application with master data. Background processing is performed for the child managed ObjectContext. Context initialization:

appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate // the moc in appDelegate is created with .MainQueueConcurrencyType mainThreadMOC = appDelegate.managedObjectContext! backgroundMOC = NSManagedObjectContext(concurrencyType:NSManagedObjectContextConcurrencyType.PrivateQueueConcurrencyType) backgroundMOC?.parentContext = mainThreadMOC 

Background processing is performed as follows:

 // download all new transaction log entries func syncItems() { ... set up the query object for parse let moc = CoreDataStore.sharedInstance.backgroundMOC // perform download moc?.performBlock( { self.runQuery(query) // Download stuff und do some core data work }) } 

The debugger shows that all the work inside the block is really in the background thread.

When I call this function from the main thread and immediately block the main thread (for testing purposes) with long-term work with kernel data, I see that the background thread stops and continues execution only when the main thread is inactive.

 // this is called from a view controller in the main thread syncItems() // should start to work in background for i in 0...200 { // do some core data work in main thread } // syncItems starts to work after the blocking for-loop ends. 

Why is this happening?

+4
source share
4 answers

Do not use the parent-child context setting.

The context of the parent child is not a good approach to anything. Just use a simple stack: two contexts with one common persistent storage coordinator.

The contexts of the parent child simply add a lot of confusion without giving you anything. This is a rather obscure concept. I wish people like mzarra to stop advocating for this attitude. Its a bad service to the community.

If your background context is a child context of your main context, you will have to block both the main and background context when you need to keep the background context. This blocks the user interface. And you will have to block the user interface a second time to propagate these changes from the user interface to the PSC. If you use a background context, you will have to merge the changes into the main context, but you will only work for those objects that are currently registered in this context. If you added new objects or updated / deleted objects that are not currently registered (via the link), this is mostly non-op.

+13
source

When you say in the comment β€œdo some basic work with data in the main thread”, is it access to mainThreadMOC ?

It seems that the main work with the thread is to block what runQuery should be accessing.

Try changing the test busy job that blocks the main thread for something that does not have access to the main data ( NSThread.sleepForTimeInterval should do), and see if the runQuery background allows it to work.

If you need this problem to refactor the main thread, work on the fact that it does not block everything that happens in runQuery .

0
source

I suspect your problem is twofold, however, even though you are doing this for testing purposes,

long work with kernel data

the user interface is blocked in the main thread, and by your definition, your backgroundMOC?.parentContext = mainThreadMOC .

I would recommend creating a more robust structure for your multiple NSManagedObjectContext s.

I recommend that you follow the steps described in this answer .

In addition, you can create an additional MOC specifically for managing your runQuery ...

 discreteMOC = NSManagedObjectContext(concurrencyType:NSManagedObjectContextConcurrencyType.PrivateQueueConcurrencyType) discreteMOC?.parentContext = backgroundMOC //MOCprivate in my previous answer. 

Hope this helps.

0
source

Regarding parent contexts, unfortunately, the last time I checked the documentation was pretty Spartan, and on the Internet you will find that almost everyone turned the thread upside down. In 2011, there was one WWDC session on master data or so, where everything was clear, and if you carefully study the API, it will start to make sense.

The child is not a context background - this is the main context. A child is a context with which you usually communicate. Parent is the background context.

The child drags the changes to the parent. This is why the parent has a persistentStoreCoordinator, but the child instead has a parentContext (he does NOT need a constant StoreCoordinator).

So, your main context is in the main (UI) queue. He saves the changes to his parent. This happens in memory (quickly - leaving the user interface as responsive as possible).

The parent context then saves its changes to the persist store through its persistentStoreCoordinator. This is why the parent is in a private queue.

 lazy var managedObjectContext: NSManagedObjectContext = { let parentContext = NSManagedObjectContext(concurrencyType: .PrivateQueueConcurrencyType) parentContext.persistentStoreCoordinator = self.persistentStoreCoordinator let managedObjectContext = NSManagedObjectContext(concurrencyType: .MainQueueConcurrencyType) managedObjectContext.parentContext = parentContext return managedObjectContext }() 

There are other optimizations, such as installing .undoManager on nil, but this general architecture works flawlessly to preserve the background.

You probably also want to add a save method that gets the block / close completion, immediately saving your child queue (which only saves in the parent, as mentioned), then calls the parentContext executeBlock method in which you will have it save (in its private queue) to the underlying persistent storage (relatively slow, but now non-blocking), and then calls your completion / closing block (which you either configured with the GCD to run in the main queue, or else you go to the main queue ttuda in the parent method executeBlock.

Everything falls into place perfectly when you do not invert the architecture. I am not sure how it is launched on the network, but this is almost a universal error.

Good luck.

0
source

Source: https://habr.com/ru/post/1244187/


All Articles