Core Data is a complicated beast that tends to trip up and infuriate many developers in the iOS community.
A quick search on Google will yield plenty of results on how people have managed to tame their NSManagedObjectContext and NSPersistentStoreCoordinator. You can also find the Core Data programming guide which is a very important read for anyone trying to use Core Data in a production application.
After banging my head against Core Data in my own applications and reading countless articles I want to highlight some of the best resources as well as provide some commentary on the basic tasks that are essential when using the Core Data framework.
Using CoreData in a multi-threaded environment
When I first started to use Core Data I quickly ran into problems. After spending more time with the framework I found two items to be extremely important.
- I needed the core classes and setup of the framework to be straightforward
- I needed to import and query data in a multi-threaded environment
With these items in mind let's talk about how we can achieve these goals.
Start with a good foundation
In order to fulfill these requirements we have to start with a good foundation and that requires setting up our NSManagedObjectContext and NSpersistentStoreCoordinator in a manner that won't get in our way when we access them from multiple threads.
When Apple introduced the ability to nest contexts people started stacking contexts together in search of better performance. Even though that is still a valid option there is a better performing setup benchmarked by Florian Kugler here. There is an example of this setup on github. Thanks to the Florian and the others behind objc.io as they have done the community a HUGE favor by providing this awesome example project and template.
Notes on the core data setup
The setup of the Core Data stack in the example is fairly simple. The NSManagedObjectContexts share a single NSPersistenStoreCoordinator. The most important part of the class may be the observation of the NSManagedObjectContextDidSaveNotification as it makes sure the main context is always kept up to date even when you are using the import contexts on background threads. For example you can import data on a background thread and your NSFetchedResultsController that is bound to your main context and main UI thread will get notified and updated properly.
Importing and querying data
So now that we have a good foundation I want to address some items on querying and importing data in an efficient manner. In order to do this we can rely heavily on the NSOperation and NSOperationQueue classes.
NSOperation and NSOperationQueue
The NSOperation class is a great way to encapsulate any block of work that you might want to do in the background. It is a high level API that sits on top of Grand Central Dispatch to use all the available processing power available on your device. The documentation from Apple is excellent as usual but it can be tricky to figure out what methods you need to override. Here are some important notes on NSOperationQueues and also some tips and resources for creating your own NSOperation subclasses.
- Create a single NSOperationQueue for all the operations within your application.
- When subclassing NSOperation be sure to override the - (NSString *)description method. This will make debugging your various threads much easier.
- When creating your own subclass you can either override the - (void)main method or the - (void)start method. Don't take the easy way out here, make sure you override at a minimum the - (void)start method in addition to the necessary properties to manage the state. If you don't implement this properly you wont be able to do asynchronous work such as network calls in your operation.
- If you need to do extra work when the NSOperation is complete use the completionBlock property to update your UI or get any results from your operation.
- Make sure to use the cancellation methods if necessary. There is no reason to leave network requests running or take up unnecessary CPU cycles.
- NSHipster has an excellent high level overview of the API.
- objc.io has a very technical explanation and examples of how to use the actual NSOperation API. Also be sure to check out their NSOperation subclass on github.
With the tips and resources above hopefully you can use Core Data in your next project and save yourself some headache!