Core Data: Getting Started Right

Thomas Lextrait
Go Ahead Tours — Tech Blog
6 min readOct 6, 2016

Core Data is a framework designed by Apple for macOS and iOS that allows persisting objects. It is essentially an abstraction of SQLite. Apple provides comprehensive guides on Core Data but given its complexity it may take a while to go through them. In this post I’ll go over the basics for getting started the right way if you are to build a modern application. I’ll also go over some of the important aspects of Core Data that may not be obvious and are often overlooked in many tutorials.

Setup

So you’ve just created a new project in Xcode and checked the “Use Core Data” checkbox (if you haven’t you’ll be missing a file, check the next paragraph for details).

By default Xcode adds Core Data related methods to your AppDelegate class. Nowadays it is bad practice to do this. In my view your AppDelegate should only manage the app’s life cycle. Core Data has become more and more complex and powerful over the years and it is best to keep your data storage code on a separate class. Definitely remove the following from your AppDelegate: everything under // MARK: — Core Data stack if you used Swift, everything under #pragma mark — Core Data stack if you used Objective-C.

Didn’t Check ‘Use Core Data’

If you didn’t check the “Use Core Data” checkbox while creating your project then your AppDelegate should be clean and you’ll just need to create one file: the data model. Right-click on your your main project folder in the Project Navigator and click “New File…”, select iOS > Core Data, then click on “Data Model”, then “Next” and follow the steps to save the file.

Entities

I won’t spend much time talking about creating entities and relationships because it’s simple, there are no tricks and there are a lot of great guides out there such as the tutsplus blog or the objc.io blog. Also check out our post by Jianghao that goes over creating entities and relationships.

Open the .xcdatamodeld file and you should have something that looks like this:

Just click the “Add Entity” button at the bottom of the screen and feel free to add some properties, change the name of your entity and play around with the editor. Now the most important part is mapping your entity to a class. Select your entity and click “Editor” in the navigation bar and click “Create NSManagedObject Subclass…”:

Select the object model, then select the entity and create the file. If using Swift, two files will be created for you (or four if using Objective-C). One class will be a subclass of NSManagedObject. This class should only carry the methods for your object, the other will be extension of that and it should carry the properties (note that the opposite also works you can have the properties on the NSManagedObject subclass and the methods on the extension). My understanding and I may be wrong about this is that we’re keeping them separate for cleanliness. For example you could have a plugin that auto-regenerates your entity classes when you change your model without overwriting your methods.

Data Storage Singleton

Now you should create a new singleton class that will provide data management methods for your app (because we removed those methods from your AppDelegate).

If you don’t have the time to read my post, you can find a very good Objective-C example here: https://gist.github.com/NachoMan/922496. However know that this code non-ARC and therefore if you want to use it for an iOS app then you’ll just need to get rid of the - (void)dealloc method. If you have the time then do check out my Threading section below as it’s important! Apple also demonstrates a slightly more sophisticated singleton available in Objective-C and Swift. If you have a few minutes then let’s go through the methods you need for that singleton one by one (in Swift):

Properties

Let’s start with a fresh class with the following properties (replace the strings on your own):

ManagedObjectModel

The ManagedObjectModel is essentially your data model, loaded from your .xcdatamodeld file. Just replace “MyApp” by the actual name of your model file. Now you may wonder why the extension is “momd”, that’s because we want to reference the compiled version of your model, which you can’t view in the Project Navigator. Add the following to your DataManager class:

Persistent Store Coordinator

The PersistentStoreCoordinator manages the actual storage of the data. Add the following to the DataManager class:

Application Support Folder

Let’s add a property that carries the location of your app’s app support folder, it is just for utility purposes (this code is a shortened version of Apple’s example):

Managed Object Context

A ManagedObjectContext is essentially a scratch pad that can be used for operations like fetching, modifying, deleting objects etc. The context is the only part of the DataManager class that you’ll use in the rest of your app to retrieve and store data.

Apple has made some changes to how the managed object contexts work in threaded environments. Fairly recently two new concurrency types were added: MainQueueConcurrencyType and PrivateQueueConcurrencyType. If you don’t specify it then the default is ConfinementConcurrencyType, which kind of replicates the same behavior you could expect before the introduction of these concurrency types. Now the part that really matters is this: retrieved objects in a ConfinementConcurrencyType or MainQueueConcurrencyType context cannot be modified from a background thread. A while back it didn’t matter much but now most mobile apps built connect to the web, download data and we deal with asynchronous operations and background threads. So how can you save data you’ve just downloaded? read the Threading section below.

Threading

Creating Private Contexts

The Core Data framework provides object contexts that are not thread-safe. Why? it’s a lot faster. Many Apple iOS and OS X frameworks are not thread-safe for the same reason. So let’s add a method to our DataManager that returns a context that’s safe to use within a thread.

This private context is setup to be a child of the main context. The nice thing about using a separate context is that you can do anything you want in that context without affecting other open contexts.

Merging Changes From Child Contexts

Now what we want is that when you save your changes to this context, they should be merged with the main context and saved to disk. To achieve this we need to listen to notifications, so lets add this to the DataManager class:

And the handler that will be called when we get notified of changes, which takes the changes from the child context and merges them with the main context:

Using Private Contexts

How do you use a private context? check my example below where I retrieve entities from the data store, modify them and save:

And here is an example where I do an asynchronous request and save data I got from a web server:

Things To Remember

  • Your main context should never be used from within a background thread.
  • You can’t pass objects from one context to another. You can re-fetch an object you retrieved in one context in another using the object’s Core Data-generated unique Id: context.objectWithID(entity.objectID).

--

--