Core Data is a framework the provides us with the ability to represent the model layer of iOS app along with persistence features.
The 2 essential CoreData framework classes to know are:
- Apple describes this as a scratchpad in-memory for app to perform core data operations. Users can later decide if they want to save ( commit) these changes to the disk
- We are allowed to create multiple NSManagedObjectContext and specify child-parent relationship among them. So any changes made to parent are automatically propagated to the child. Any changes made to the child are propagated to the parent when child.save() is called
- All the data stored in the Core Data database , when retrieved in memory is represented by Core Data framework in form of NSManagedObjects
In the most standard scenarios, we can get away with single NSManagedContextObject created with MainQueueConcurrencyType. In this case, all the Core Data operations happen on the main queue along with UI related actions. This setup is recommended only if the core data actions support the user actions ( Eg: A new TODO item has been created, an existing work item is marked completed etc).
But for certain apps, the core data operations do not have direct correlation with user’s scenario. Eg: Import operations, storing network data in background so that user’s can access it later, if necessary. As for any multi-threaded system operations that do not directly correlate with user scenario should be performed on a background thread/queue. Core Data framework hence provides us with the option of creating a NSManagedContext with PrivateQueueConcurrencyType. It goes a step further and also creates a private queue that is exclusively reserved for this NSManagedContext object.
Below are some of the rules that must be followed if you do not want your app that uses CoreData to crash (or) corrupt the database:
- A NSManagedObjectContext should be used only on the queue that is associated with it.
- If initialized with .PrivateQueueConcurrencyType, a private, internal queue is created that is associated with the object. This queue can be accessed by instance methods .performBlockAndWait (for sync ops) and .performBlock (for async ops)
- If initialized with .MainQueueConcurrencyType, the object can be used only on the main queue. The same instance methods ( performBlock and performBlockAndQueue) can be used here as well.
- An NSManagedObject should not be used outside the thread in which it is initialized
In order to stress the importance of these rules, Apple has associated a scary name when these rules are not followed – “Core Data Violations”. In fact, Apple considered these violations so important, that they decided to start crashing when a CoreData violation is present, starting iOS 6. But there were already so many apps in App Store and most of them would start crashing and so Apple to turn it OFF.
Today it is still possible to get your app into AppStore with Core Data Violations in it. Refer to this blog post to understand how to enable this detection when developing your app. When this Core Data Violations detection is enabled, all violations of Core Data threading rules will cause debugger to stop with stack trace ending at
and hence the title of this blog post