I am new to iOS dev. I am writing an iOS app that allows the user to read/write core data records. These records are to be synced to a server across http. I have a set of chained (serially) NSOperations running in a background thread that perform the sync.
The user can read/write at the same time as the sync us running. My plan is to use two managedObjectContexts within the app (both using the same persistentStoreCoordinator), one for foreground and one for background.
All background threads created by my NSOperations will run serially and will use the background MOC. All UI-based stuff will use the foreground MOC.
My question is this: is this an acceptable iOS core data pattern? Can I happily have reads/writes occurring against the same model database within these two MOCs without worrying about locking and concurrency issues?
Thanks very much.
This is a common core-data pattern and one the framework was designed to accommodate.
If you are managing the threads yourself you need to use a technique called "Thread Confinement" you can read more about it in the documentation in the section titled "Concurrency with Core Data".
In addition to thread confinement, there are also new features in iOS 5.0 designed to help manage concurrency. An NSManagedObjectContext can now be configured with a NSManagedObjectContextConcurrencyType. You can chose between a NSMainQueueConcurrencyType and NSPrivateQueueConcurrencyType.
A context with NSMainQueueConcurrencyType runs on the main thread and can be used to serve the UI. A context with NSPrivateQueueConcurrencyType is used for background tasks.
To use the private context you interact with it through the performBlock: and performBlockAndWait: methods to ensure your code is executed on the correct thread. To use the main queue context you can interact with it as normal, or if your code is not running on the main thread, by using the block methods.
These new features are not discussed in great detail in the documentation, there is some information in the section "Core Data Release Notes for iOS v5.0". However there is a much more insightful discussion in the WWDC 2012 session video: "Session 214 - Core Data Best Practices".
Related
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.
I have seen many times people use many managedObjectContext, but aside from when using the Undo manager, what is the real reason for using multipleManagedObjectContext? Why can it be useful to use more than one? Could you please show a few examples?
Managed object contexts are not thread safe so if you ever need to do any kind of background work with your Coredata objects (i.e. a long running import/export function without blocking the main UI) you will want to do that on a background thread.
In these cases you will need to create a new managed object context on the background thread, iterate through your coredata operation and then notify the main context of your changes.
You can find an example of how this could work here Core Data and threads / Grand Central Dispatch
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.
I'm beginning to think the answer to my question is 'No', but I'm still confused and uncertain about this. So please confirm. I've already learned the need to be careful when using Core Data with multiple threads. NSManagedObjectContext objects must not cross thread boundaries. Being a newbie with both threads and Core Data, I happily found that GCD should make some of this easier.
Naively perhaps, I then thought I would simply create a dedicated GCD dispatch queue for dealing with Core Data (or even, if needed, have multiple dispatch queues each with its own core data context). That would have been simple.
But now I realize that one big advantage of GCD dispatch queues is that it manages and makes use of multiple threads as needed. So - if I understand this right - tasks I hand off to one and the same dispatch queue, could end up running in different threads, potentially handing off a core data context from one thread to another, and having things go wrong. Is that right?
I've read many related questions and answers, for example Core Data and threads / Grand Central Dispatch, but I remain somewhat confused. The accepted answer to that question, using GCD queues, does ensure that a new context is created on each thread, but does not point out the necessity of doing this. Another answer says "You could execute all CoreData work on a queue named com.yourcompany.appname.dataaccess" seeming to imply that as long as the Core Data work is confined to one GCD dispatch queue, then all is OK. Maybe it is not.
Update: As #adib points out in a comment, the approach to serialized managed object context (MOC) access has changed in iOS 9 and MacOS X 10.11. NSConfinementConcurrencyType, the thread confinement strategy, is now deprecated in favor of NSPrivateQueueConcurrencyType and NSMainQueueConcurrencyType. In other words, stop using threads for concurrent access to Core Data objects and instead start using GCD. You should use either the main dispatch queue or the one associated with the MOC, depending on how you configure the MOC, and not a queue of your own creation. This is easy to do using NSManagedObject's -performBlock: or -performBlockAndWait: methods.
Short answer: Using a serial dispatch queue can provide serialized access to a managed object context, and that's an acceptable way to implement the "thread confinement" strategy even though GCD may actually employ multiple threads.
Longer answer:
The accepted answer to that question, using GCD queues, does ensure
that a new context is created on each thread, but does not point out
the necessity of doing this.
The big thing you need to remember is that you must avoid modifying the managed object context from two different threads at the same time. That could put the context into an inconsistent state, and nothing good can come of that. So, the kind of dispatch queue that you use is important: a concurrent dispatch queue would allow multiple tasks to proceed simulaneously, and if they both use the same context you'll be in trouble. If you use a serial dispatch queue, on the other hand, two or more tasks might execute on different threads, but the tasks will be executed in order, and only one task will run at a time. This is very similar to running all the tasks on the same thread, at least as far as maintaining the context's consistency goes.
See this question and answer for a much more detailed explanation.
This is how Core Data has always worked. The Concurrency with Core Data section of the Core Data Programming Guide gives advice on how to proceed if you do decide to use a single context in multiple threads. It talks mainly about the need to be very careful to lock the context any time you access it. The point of all that locking, though, is to ensure that two or more threads don't try to use the context simultaneously. Using a serialized dispatch queue achieves the same goal: because only one task in the queue executes at a time, there's no chance that two or more tasks will try to use the context at the same time.
AFAIK you're correct; GCD doesn't make guarantees about the thread in which the queue is run. Blocks and function calls sent to the queue will be run one at a time, but if Core Data does something with the current thread, e.g. installs a run loop source or observer, things probably won't work as intended.
However, on Mac OS X 10.7, NSManagedObjectContext can be set to run on the main thread, on a separate thread, or in a private queue.
The Apple "Concurrency with Core Data" documentation states the following when discussing using core data with background threads.
Saving in a Background Thread is Error-prone
Asynchronous queues and threads do not prevent an application from
quitting. (Specifically, all NSThread-based threads are “detached”—see
the documentation for pthread for complete details—and a process runs
only until all not-detached threads have exited.)
and in particular:
If you need to save on a background thread, you must write additional code such that the main thread prevents the application from quitting until all the save operation is complete.
What is the recommended approach for achieving this inside an IOS application?
In the app delegates applicationWillTerminate and related methods, you need to check if any background threads have unsaved changes and save them before allowing the app to terminate or go into the background.
I recommend taking a look at using Magical Record (https://github.com/magicalpanda/MagicalRecord/). It greatly simplifies dealing with core data on background threads. I recently found this and used it for a project. We've now undertaken a maintenance effort to update a variety of existing apps to use the new Magical Record Core Data wrapper. It has saved us tons of time and frustration in the few weeks we have been using it.