Use global managed object contexts to support concurrency - ios

I haven't ever found an answer to this when reading developer documentation.
When using main and private queue contexts in Core Data is it a good strategy to use a global NSPrivateQueueConcurrencyType and NSMainQueueConcurrencyType contexts that I can access across my app and for the entire lifetime of my app?
Or, should I be creating a new instance each time I need to use a NSManagedObjectContext?
I have used this documentation but it doesn't answer the question.

In most cases the current best practice is to start with NSPersistentContainer. Its methods point to good practices for dealing with managed object contexts.
NSPersistentContainer has a property viewContext which uses a main queue concurrency. As its name implies, it's good for use directly with the UI, and on the main queue. Use this context for those cases. Don't create new main queue contexts.
It also has a couple of ways to do background work on private queues, via newBackgroundContext() and performBackgroundTask. In most cases you can use either of these when you need to do background work, and not bother keeping a reference to a long-lived background context. One caveat is that since they use separate background queues, it's possible for one background context to be executing at the same time as another. If that seems possible in your case, you might want to hold onto a background context to avoid that possibility. Otherwise your background contexts might need to merge changes made on other background contexts, which can get ugly fast.
There are exceptions to all of the above, but this is a good starting point. If this doesn't fit with your app for some reason, come back with another question detailing why.

I would recommend you to do write on a different context and then merge it back.
As a good practice i can recommend the setup MagicalRecord uses.
Specifically they use a Default Context as a Child of a RootSavingContext. Then All writes go into a new context and then get merged into the root context.
This way the default context can be used in the main thread and gets proper update notifications, e.g. for use with a FetchedResultsController.

Related

Best setup of managed object contexts

I have read several tutorials that recommend using two (or more) NSManageObjectContexts when implementing core data, so as not to block the UI of the main queue. I am a little confused, however, because some recommend making the child context of the persistent store coordinator that of type mainQueueConcurrencyType, and then giving it its own child context of type privateQueueConcurrencyType, while others suggest the opposite.
I would personally think the the best setup for using two contexts would be to have the persistent store coordinator -> privateQueueConcurrencyType -> mainQueueConcurrencyType, and then only saving to the private context, and only reading from the main context. My understanding of the benefits of this setup is that saving to the private context won't have to go through the main context, as well as reading on the main context will always include the changes that are made on the private context.
I know that many apps require a unique solution that this setup might not work for, but as a general good practice, does this make sense?
Edit:
Some people have pointed out that this setup isn’t necessary with the introduction of NSPersistentContainer. The reason I am asking about it is because I’ve inherited a huge project at work that uses a pre-iOS-10 setup, and its experiencing issues. 

I am open to re-writing our core data stack using NSPersistentContainer, but I wouldn't be comfortable spending the time on it unless I could find an example of how it should be setup with respect to our use cases ahead of time.
Here are the steps that most of our main use cases follow:
1) User edits object (eg. adds a photo/text to an abstract object).
2) An object (sync task) is created to encapsulate an API call to update the edited object on the server. Sync tasks are saved to core data in a queue to fire one after the other, and only when internet is available (thus allowing offline editing).
3) The edited object is also immediately saved to core data and then returned to the user so that the UI reflects its updates. 

With NSPersistentContainer, would having all the writing done in performBackgroundTask, and all the viewing done on viewContext suffice for our needs for the above use cases?
Since iOS10 you don't need to worry about any of this, just use the contexts NSPersistentContainer provides for you.

Core data multithreading performance

I am developing an application that uses Core Data for internal storage. This application has the following functionalities :
Synchronize data with a server by downloading and parsing a large XML file then save the entries with core data.
Allow user to make fetches (large data fetches) and CRUD operations.
I have read through a lot and a lot of documentation that there are several patterns to follow in order to apply multithreading with Core Data :
Nested contexts : this patterns seems to have many performance issues (children contexts block ancestor when making fetches).
Use one main thread context and background worker contexts.
Use a single context (main thread context) and apply multithreading with GCD.
I tried the 3 mentioned approaches and i realized that 2 last ones work fine. However i am not sure if these approaches are correct when talking about performance.
Is there please a well known performant pattern to apply in order to make a robust application that implements the mentioned functionalities ?
rokridi,
In my Twitter iOS apps, Retweever and #chat, I use a simple two MOC model. All database insertions and deletions take place on a private concurrent insertionMOC. The main MOC merges through -save: notifications from the insertionMOC and during merge processing emits a custom UI update notification. This lets me work in a staged fashion. All tweets come in to the app are processed on the background and are presented to the UI when everything is done.
If you download the apps, #chat's engine has been modernized and is more efficient and more isolated from the main thread than Retweever's engine.
Anon,
Andrew
Apple recommends using separate context for each thread.
The pattern recommended for concurrent programming with Core Data is
thread confinement: each thread must have its own entirely private
managed object context. There are two possible ways to adopt the
pattern: Create a separate managed object context for each thread
and share a single persistent store coordinator. This is the
typically-recommended approach. Create a separate managed object
context and persistent store coordinator for each thread. This
approach provides for greater concurrency at the expense of greater
complexity (particularly if you need to communicate changes between
different contexts) and increased memory usage.
See the apple Documentation
As per apple documentation use Thread Confinement to Support Concurrency
Creating one managed object context per thread. It will make your life easy. This is for when you are parsing large data in background and also fetching data on main thread to display in UI.
About the merging issue there are some best ways to do them.
Never pass objects between thread, but pass object ids to other thread if necessary and access them from that thread, for example when you are saving data by parsing xml you should save them on current thread moc and get the ids of them, and pass to UI thread, In UI thread re fetch them.
You can also register for notification and when one moc will change you will get notified by the user info dictionary which will have updated objects, you can pass them to merge context method call.

How to dynamically use MOC depending on thread to protect core data

I've read through the materials regarding core data and threading and understand the principles of a separate MOC for each thread. My question is, what's the best way to dynamically determine whether to use a different MOC or the main one. I have some methods that are sometimes called on the main thread, sometimes in background. Is dynamically detecting thread not recommended or is it okay? Any pitfalls? Or do people just write separate methods for the background processes?
Some additional detail...i have a refresh process that performs a bunch of updates off the main thread (so not to lock the UI while user is waiting) using a simple performSelectorInBackground. This process moves thru steps serially so i dont have to worry about multiple things accessing DB on THIS thread, obviously the trick is keeping the main and background safe. I have implemented using a separate context and merging in other places, but i recently rearchitected and am now using methods in the background i wasnt before. So i wanted to rewrite those, use the separate context, but sometimes ill be hitting them on the main thread and can access main MOC just fine.
You do not give much detail about how you are managing your background operation and what you are doing with it, so it is pretty difficult to suggest anything.
In general, since creating a MOC is a pretty fast operation, you could create a new temporary MOC each time you need one in read-only mode (e.g. for data lookup). If you also have updates (e.g., adding new object or modifying existing ones), you should factor in the cost of merging, thus creating temporary MOCs each time could not be a good approach.
Another good approach could be creating a child context in your background thread.
But, as I said, it all depends on what you are doing.
Have a look at this good post about multi-threaded Core Data usage: Multi-Context CoreData. It describes a couple of scenarios and the solutions for them.
EDIT:
You could certainly use isMainThread to discriminate between the two cases (where you can use the main MOC and when you need a new one). That is what that method is for (and it is surely not expensive).
On the other hand, if you want a cleaner implementation, the best approach IMO would be creating a child MOC (which simplifies a lot the merging process - it becomes almost automatic, since you just need to save the parent context after saving the temporary context).
You'll need a new NSManagedObjectContext for each thread, and you'll need to create new versions of your NSManagedObjects from that thread's new MOC. Read #sergio's answer regarding the pros/cons of that approach.
To check if you're on the main thread, you can use [NSThread isMainThread] and make determinations that way. Or, when you're spinning up a new thread to crunch on CoreData, also create a new MOC.
A common approach is to associate each managed object context with a particular serial dispatch queue. So there's one for the main queue, and you can dynamically create them otherwise.
Once you're tying these things to queues, you can use dispatch_queue_set_specific to attach a particular context to a particular queue and dispatch_get_specific to get the context for the current queue. They both turned up in iOS 5 so you'll see some iOS 4-compatible code that jumps through much more complicated hoops but you don't really need to worry about it any more.
Alternatively, if your contexts are tired to particular NSRunLoops or NSThreads, store the context to [[NSThread currentThread] threadDictionary] — it's exactly what it's there for.

Is there a way to figure out what thread an NSManagedObjectContext is on?

My understanding of threads with respect to an NSManagedObjectContext is that it can only execute core data fetch requests, deletes, etc., on the thread from which it was created. Is there any way to check to see what thread an NSManagedObjectContext was created on, or if at a particular point of execution the current thread is that of a particular NSManagedObjectContext?
Thanks!
My understanding of threads with respect to an NSManagedObjectContext is that it can only execute core data fetch requests, deletes, etc., on the thread from which it was created.
That's not really accurate. It would be better to say that contexts cannot be used concurrently by more than one thread or queue. A common approach to dealing with this is to create different contexts for each thread/queue. It's also possible to use the performBlock and performBlockAndWait methods to use contexts on multiple threads while keeping context access effectively single-threaded.
As a result, contexts don't have any notion of belonging to a thread or queue, nor do threads have any reference to contexts that were created on them.
If you follow the approach of one context per thread or queue, you need to keep track of where code will run and use the appropriate context. For example when using GCD, create a context for a specific dispatch queue, and only use it when you've used something like dispatch_async to run on that queue.
If you really want to link a context with a queue, you could use your own data structure to look up contexts from whatever concurrency scheme you're using-- by the current NSOperationQueue, or dispatch queue, or NSThread, or whatever. This is rarely needed, but it's a possibility if you can't find better techniques.
As far as I know you can't. At least not too easily. Why? Use -performBlock: - it will perform all requests on the correct thread.
Sorry Tom Harrington, but that's actually not at all correct. Although you can technically do this, the results will be random and usually (in my experience) result in race conditions that become extremely difficult to debug.
The DOCs explicitly indicate that you should use a context PER thread. In fact even some of the best frameworks around (i.e. MagicalRecord) behave in this way. NSManagedObject's and their contexts are NOT thread safe, however objectIDs are.
To check for changes, you could either persist your changes up to the parent context's or you can listen to the notifications provided. Using the second method, you'll then need read the objectIDs of the item(s) you want to access, then request them again from your local context.
Read the following Apple Documentation to better understand how this works.
https://developer.apple.com/library/ios/documentation/cocoa/conceptual/coredata/Articles/cdConcurrency.html
After further research I have found a document last updated over the past few weeks and although you are correct in regards to the performBlock methods it does still state that you should not pass contexts between threads. Perhaps I misread the question and responded a little quickly. I've recently been working on a large CoreData based application and I know we have had a lot of issues related to contexts and threads, so I responded a little quick. ;)
https://developer.apple.com/library/mac/documentation/Cocoa/Reference/CoreDataFramework/Classes/NSManagedObjectContext_Class/NSManagedObjectContext.html

Core Data stack with only a single context initialized with NSPrivateQueueConcurrencyType

I'm working on an app that requires multiple asynchronous downloads and saving of their contents to Core Data entities. One of the downloads is large and noticed the UI was being blocked while creating/writing to the managed object context. My research led me to read up on concurrent Core Data setups and I started implementing one of these. But I'm running into issues and spending a lot of time correcting things.
Before I continue, I'm thinking about simply setting up a single MOC with NSPrivateQueueConcurrencyType. Nothing I read mentions doing this. This way I could optionally perform MOC operations in the background, or just use the main thread as usual while maintaining a single MOC.
Is this a good approach? If not, what is wrong with it? I doubt this is the right approach because if it is, NSPrivateQueueConcurrencyType dominates NSMainQueueConcurrencyType and there would be no reason to have the latter.
There is nothing wrong with using a NSPrivateQueueConcurrencyType MOC for background tasks.
But you will probably still need a NSMainQueueConcurrencyType MOC.
From the documentation:
The context is associated with the main queue, and as such is tied
into the application’s event loop, but it is otherwise similar to a
private queue-based context. You use this queue type for contexts
linked to controllers and UI objects that are required to be used only
on the main thread.
As an example, for a fetched results controller, you would use the
NSMainQueueConcurrencyType MOC.

Resources