I read in a few places (like a high score answer here) that it's good pratice to make main managed context child of a background manaaged context to save save() time and improve UI responsiveness.
Persistent Store Coordinator
↑
Managed Object Context (for saving) <= note this
↑
Managed Object Context (main)
↑
Managed Object Context (for editing)
But the issue is that the main managed context created by iOS template code is associated with Persistent Store Coordinator and there doens't seems to be a supported way to change that. I tried the following code:
lazy var persistentContainer: NSPersistentContainer = {
// Template code: create persistent container
// ...
// My code
let saveMOC = container.newBackgroundContext()
container.viewContext.persistentStoreCoordinator = nil
container.viewContext.parent = saveMOC
return container
}()
but got an NSException:
uncaught exception 'NSInternalInconsistencyException', reason: 'Context already has a coordinator; cannot replace.'
My questions are:
1) Does that mean, to implement the architecture above, I can't use NSPersistentContainer and have to set up the Core Data stack with my own code?
2) Given that NSPersistentContainer is the new API, I think it must have some way to achieve the same effect (saving managed object changes in background thread). I wonder what's it? I'm thinking about the following approach, where save() is invoked only in the saving context, rather in the main context. But it is more complex and doesn't fell as natural as the the above one. Is there any simpler approach?
Persistent Store Coordinator
↑ ↑
Context (main) --merge--> Context (saving)
↑
Context (editing)
UPDATE: On a second thought, this approach doesn't work because merge is based on notification. If save() is not invoked in main context, there won't be any notification triggered.
Hmm, I'm wondering if it's OK to create another NSManagedObjectContext of mainQueueConcurrencyType, set it up as I'd originally like and then replace the one created by NSPersistentContainer with it?
Thanks for any suggestions.
I think I probably find a solution:
automaticallyMergesChangesFromParent
to true.This means that everytime a managed object is edited in private context, a save() call should be invoked immediately.
One cornor case, I think, is that user suspends the application when the save() call is invoked, which may cause main context update view while the view has been removed from screen. But I think this may happen even without Core Data multithreading, so I think UIKit should be able to handle this scenario properly.