Core Data Multiple ManagedObjectContext - ios

How the multiple ManagedObjectContext (MOC) works in core data(Swift 2, iOS 9). I have been through lots of links & material online and answers on StackOverflow, but couldn't find exact answer.
I want to know, suppose I have created main MOC which points to PersistentStoreCoordinator (PSC)and another private queue MOC which has parent context set to above mentioned main MOC.
Question 1: Then How this works ? Is the hierarchy built like this : Private queue MOC --> Main queue MOC --> PSC.
Question 2: If I call save on 'private queue MOC', will it save to main MOC and in turn automatically main MOC will save to PSC ? or After save on Private MOC we have to call explicit save on Main MOC to save it to PSC ?
I just started working on core data and online links are not so clear. So, any simplified explanation will be much appreciated.
Thanks!

For question 1, the hierarchy is however you create it. If you create a context with no parent, and then another one whose parent context is the first context, it'll be as you describe.
For question 2 I'll turn to the documentation on NSManagedObjectContext:
When you save changes in a context, the changes are only committed “one store up.” If you save a child context, changes are pushed to its parent. Changes are not saved to the persistent store until the root context is saved.
Saving is never automatic, so the parent context doesn't save changes until you tell it to save.

Related

Concurrency in CoreData with multiple contexts

There are few ways of handling concurrency in CoreData
One of them is using parent/child managedObjectContexts like so:
let mainContext = NSManagedObjectContext( concurrencyType: .MainQueueConcurrencyType)
let childContext = NSManagedObjectContext( concurrencyType: .PrivateQueueConcurrencyType)
childContext.parentContext = mainContext
Another approach would be to have both the main and child contexts use the same persistentStoreCoordinator like so:
let mainContext = NSManagedObjectContext( concurrencyType: .MainQueueConcurrencyType)
let childContext = NSManagedObjectContext( concurrencyType: .PrivateQueueConcurrencyType)
childContext.persistentStoreCoordinator = mainContext.persistentStoreCoordinator
Since we'll need to use performBlock on the childContext and later save or execute fetch or anything on the mainContext, what would be the difference between these two approaches?
I read on Florian Kugler's blog that the former approach processes on the Main Thread (which I tried and it didn't) and the latter is the preferred way. But every other site that I've looked seem to prefer former parent/child context.
To make things more confusing, on RayWenderLich's CoreData book (chapter 10 for references), they've used both of the approaches without explaining why.
Ideally there are 3 simple rule to achieve concurrency in single persistentStore core data application.
only one Managed Object context (MOC) should attached with persistentStoreCoordinator is basic rule to avoid MOC lock, unlock on CURD operation.
Every MOC should attached with one thread like Main thread MOC, background thread MOC.
You can not pass the managed object from one MOC(thread) to other by MOC(thread), in this case just pass ObjectID.
To achieve all three rule, apple introduce parent- child MOC approach. There are so many combination on various post,
But each stack (parent- child MOC approach) is highly depend on the application data usability.
I have implemented as my main MOC contexts use persistentStoreCoordinator, And created background thread child MOC for data synchronisation,
and more local child MOC for each View controller for creating new records screen. this will work well for me and tested with 3500 records insertion on DB.
The benefit doing this I am getting the updated server sync data through my main MOC.
I know few critics for approach, that I will block the main thread, But you can utilise batch update, delete, asynchronous fetch request to minimise it.

Use NSManagedObject in child NSManagedObjectContext instead of its parent

I have two MOCs: the first is the root context. When I save this context, the changes are saved to the persistent store coordinator. The second MOC has the first MOC as the parent. When I save the second MOC, I also have to save the first MOC in order to save the changes in the second MOC to the persistent store coordinator.
I use the second MOC to let the user edit an object. He can save or cancel the changes. When he saves the changes, all MOCs are saved. When he cancels the changes, I call rollback() of the second MOC.
Unfortunately, the object comes from the first MOC. This means, I execute an NSFetchRequest to fetch the object on the first MOC. Then I create the second MOC in which the user can edit the object. But there is a problem: when the second MOC should change something, for example delete an object that is contained in an array of the original object the user wants to edit, this is not possible, because a MOC can only delete objects that have this MOC as the context. But the object was fetched in the first MOC.
That's why I need to "transfer" somehow the object from the first MOC to the second MOC before the user edits the object. I don't want to fetch the object again with a NSFetchRequest or something, there must be a better way…
Is this possible? Or do you recommend to do this completely different, maybe without parent contexts?
This is where the objectID property of NSManagedObject will come in handy.
Ask the object for its ID
let objectID = myManagedObject.objectID
Ask the child context for a managed object with that ID
do {
let childManagedObject = try childContext.existingObjectWithID(objectID)
print("\(newObject)")
} catch {
}
I think you might be complicating your time with this. Unless it is completely necessary for proposed changes to also be saved there should be no reason to have two contexts for this. There are multiple ways for you to handle a temporary data which you can use to compare your actual record to without having it stored twice.
Why don't you just create a copy of the NSManagedObject and handle the information correction by comparison or simply replacing the original NSManagedObject with the data of the copy and then save it? I personally like this setup a bit more since all I have to do is either compare individual properties when update is desired.
When a full update is required than you can simply work directly on the one NSManagedObject without worrying about copies since you will probably be replacing the entire thing anyway. Like I said, there are other ways to handle, but if it is absolutely necessary for you to have both contexts then looking for a comparison of each property value to the replaced value and then simply save the one in the parent context.

Some unkown NSManagedObjectContext

I'm working a multithread core data project. I set up the core data stack as follows:
Create Only One persistStoreCoordinator
Create Two NSManagedObjectContext, both set their coordinator to persistStoreCoordinator, so these two contexts(one is main context of main current type and another is background context of private queue type) are in same level, not parent-child hierarchy.
This core data stack is hold by my Singelton class. So init only once.
After doing this. I create a view controller to test this. However, even when I do nothing on core data stack. I found the callback for NSManagedObjectContextDidSaveNotification are triggered. And the notification.object(which is a NSManagedObjectContext) is neither my main context nor my private context. And its persistCoordinator is not the same as the one I created.
So does anyone met this problem before or Can anyone of u give me some idea to track this problem?
Thanks in advance.

Is it valid to mix the "1 moc per thread" strategy with "child moc" strategy?

Until now I always used a "main moc" for the main thread, initialised like this:
[[NSManagedObjectContext alloc] init];
and then I have NSOperation subclasses with their own moc that import data from the webservice, and I merge in the "main" moc on save observing NSManagedObjectContextDidSaveNotification
But now I need the ability to add "temporary" objects that the user can commit (or not) later. So it looks like a child context is the perfect fit, and in order to use child context I changed the initialization of my "main moc" to
[[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
The question is: can my current structure with NSOperation subclasses with their own moc (initialised without a type in their own thread) have problems if used along with the child context strategy? I don't think so, but I don't find much about mixing those strategies.
Note that I want to maintain the NSOperation subclasses and I don't want to use child contexts also for importing my data, because it suffers on performances, see http://floriankugler.com/blog/2013/4/29/concurrent-core-data-stack-performance-shootout
Moreover, when I create a new child of my main thread (that is of type NSMainQueueConcurrencyType), can I create it that child with type NSMainQueueConcurrencyType, continuing to work with my objects in the main thread as usual? Or am I forced to use NSPrivateQueueConcurrencyType, and use performBlock: for every operation on my objects?
I'm asking because is not clear from the documentation if using 2 moc on the same thread (the main thread in this case) could be a problem.
UPDATE:
Finally I implemented and used this solution on production and there are not problems so far. The only thing that I needed to do is to avoid merging on my NSManagedObjectContextDidSaveNotification notification when the moc has a parentContext (we don't want to merge mocs with a parent context, because they manage the merge themselves, but obviously the notification is triggered also for save on this kind of moc)
Yes, you can have multiple main queue context mocs, for exactly the reason you say - you create a temporary editing context for editing data which is then saved or discarded depending on user action.
As for mixing and matching with your operation queue contexts - that shouldn't be a problem. If you're merging back to the parent context, then any child contexts will pick up that data the next time they fetch.
Actually, that's indicated when working with multiple threads. Here, I've wrote an article exactly about this. The slave mocs mentioned in it, are designed exactly for working with operations, each operations on it's own slave moc.

NSManagedObjectContext - How to associate childcontext data with parentcontext data?

I'm confused on how the a child MOC (NSPrivateQueueConcurrencyType) works with a parent MOC (NSMainQueueConcurrencyType) with respect to the following scenario. I need to has a background thread check a web server for new or updated data. When something is received, I need to save or update the parent MOC. Sounds simple enough, and I see various examples. However, I'm still confused on a couple of things.
When processing data in the background thread, I can easily save the object in the child MOC. However, in my data model, I have relationships set up as recommended. So, for example, a ConversationThread will contain an array of Messages. Each Message will have Message.parentConvoThread set in the relationship. So, whenever I'm getting new messages from the server...
How do I associate the new Message object, which is created in the child privateMOC, with the ConversationThread (currently in the parent mainMOC)?
Now, say that I'm getting updated personal info for the person who wrote the message. I see they have updated data on the server, so I need to update their data in app. In the privateMOC...
How do I get the actual object (say it's MyContact) from the mainMOC to explicitly update? or...
If I create a new MyContact in the privateMOC, how do I merge that with the currently existing MyContact in the mainMOC? ...or does it automagically happen somehow? (<- I've read a lot of older threads that say you to use NSManagedObjectDidChangeNotification and manually merge but that this isn't necessary anymore...but how/why?)
Finally, a couple of questions about searching...
Can a search against the child privateMOC return results from the parent mainMOC (say if an entity exists in the parent but not the child)?
If the answer to #1 is true, what happens if the entity exists in both but hasn't been merged?
I'm quite confused on how they work together. Any help is greatly appreciated.
NSManagedObjectContexts are in memory caches of the data from an NSPersistentStore. A fetch on a child context will be executed through the parent context on the NSPersistentStore, and the data from the objects will be retrieved from either the cache in the child context, the parent context, or all the way from the persistent store (wherever it can first find the data).
If you are fetching from a child context, the results will be retrieved through the parent context, and you can expect this fetch request to return objects as though you fetched from the parent context.
Going the other direction, as long as all the changes you have made to your child context have been saved, those changes will be reflected in the parent context, because core data automatically handles the merge from child to parent.
The only trick is if you have references to objects in the child context, and changes are saved in the background to the parent context, you will either need to re-fetch those objects on the child context to get changes from the parent, or you can manually merge the changes on the parent's NSManagedObjectContextDidSaveNotification. See this post for more information: How to keep a child NSManagedObjectContext up to date when using bindings.

Resources