I have an NSManagedObjectContext
associated to main thread (mainContext
), where I fetch all the NSManagedObject
I show throughout the app.
Users don't edit these objects, but I get updates from web services. I periodically perform asynchronous calls to such services, and they "tell" me which of my managed objects have to be deleted (if any), which of them have to be updated with new information (if any), and if I need to insert new objects.
So, I need to firstly get the responses of all the services and then check what changes I have to make to the managed objects I already have in my mainContext
. And I also need to perform the updates avoiding blocking the UI.
I was thinking about 2 ways to manage this scenario:
- To use a completely separated
privateContext
in a private queue with its own Core Data stack to insert there all the objects I get from services. Then compare somehow (how?) with the objects I have inmainContext
, and delete/modify/insert objects that are there inmainContext
. - To use a
privateContext
in a private queue, but being a child of themainContext
. I'd then need to pass the child context the objects I have in its parentmainContext
(is this possible? how?), and at the same time insert in this child context the objects I get from services, and then compare and perform changes.
What of the approaches would be the best or the appropriate one? Or maybe should it be a different one I haven't thought about?
Thanks in advance
EDIT: Could this be another possible way?:
- Only use the
mainContext
and, as I'm parsing the responses of the services, instead of creating the new objects just make changes onmainContext
one by one...
EDIT 2: Another possibility?:
- Only use the
privateContext
, get the services responses and create the new objects. Then, also fetch with thisprivateContext
all the objects that already existed (and that would be the same as the objects inmainContext
). Make changes in thisprivateContext
comparing the two sets of objects (the recently created from services and the fetched), save this context, clearmainContext
and re-fetch all objects inmainContext
.
I'm not sure this is a full answer for you but I'm working on a somewhat similar situation. The implementation path I've taken is to use child objects (all over the place) - or more like temporary child context's as needed.
The first thing I should mention, however, is make sure to use the CoreData debug functionality build into XCOde. I made a second Run-Scheme that has
-com.apple.CoreData.ConcurrencyDebug 1
On application init I have my normal
NSManagedObjectContext
- which is passed around to my background networking thread.Then whenever I need to pass something from parent to child I end up doing:
or I end up doing
I can't say I really "love" this approach and I'm sort of stuck with it for the moment however it does seem to work well enough.
Between most of my view controllers I have a
And in my
prepareForSegue
methodSummary
CoreData
because no matter how you look at itCoreData
is not the most threading friendly option.UDPATES
Save Code
I actually save to the child context every 50 messages and to the parent every 250 it looks like (haven't touched this code in ages). I can't promise this is the best correct way to do things but it does work and it does keep disc access to a minimum. I am getting A LOT of messages like 20+ a second so i wanted to do this stack type. You may not care
(self.getChild()) returns the child context - its older code i left here.
Deleting
...
Again - like i said before this may not be the best way of doing things but i do have a parent/child stack and it does work. This was one of the first iOS apps I wrote and to do it over again i'd punt on core data and use something else.
We had an extremely high update rate so when we were using a single stack it was making the UI very slow. The migration to parent/child was slow - were i to do it again I think it would have gone smoother because i'd write many helper functions to deal with some of this (or just use swift).
good luck.