There are 3 main stages of Core Data: Modeling, Saving & Fetching. We start by building a Data Model with the Entities we want to persist. Then we save the instances of those entities that are in our Managed Object Context. Then we can fetch those saved instances (Managed Objects) from our context. Optionally, we can filter and sort those fetched objects.
NOTE: This post assumes you set up the Core Data stack already. If you haven’t, it might be helpful to look at the post on Apple’s Core Data Boilerplate code.
Modeling is the first and most important part of Core Data. Poor modeling will make the rest of Core Data a pain to deal with. So do it right from the start. So what do we mean by modeling? Well, modeling our entities … which is very similar to how we model our classes. Before we go through how that looks, let’s start by making a Data Model file.
So start by opening the New File window either by going from File > New > File or by using Cmd+N. Then under iOS, go to Core Data and choose Data Model.
Give it a name and save it. Now when you open it, you’ll get a window looking like this:
Before we start modeling entities, let’s see how we would model a Dog object.
Notice how we have 4 properties: name, breed, weight, and owner. Now let’s make a Dog entity.
We add a new entity by either clicking the Add Entity button at the bottom or by going to Editor > Add Entity.
It’ll give us an empty Entity with “Entity” as the default name. You can double click it to change the name. We name Entities the same way we name Classes, in PascalCase (the first letter of every word is capitalized).
So we have a Dog Entity. Now we have to add the properties. Notice the three tables on the right.
You can think of attributes as a general property. In fact, they’ll become properties of the managed objects. They’re the data of the entity. So if we want to add our properties, we should start by adding the attributes.
Note: Because attributes become properties of the managed objects, you can’t name your attributes certain things like “description” since NSObject already has a description property thus your managed object will inherit it.
To add an attribute, either press the + button under the attributes table or the Add Attribute button on the bottom right or go to Editor > Add Attribute.
Just like before, it’ll get a default name and a type of undefined. So give it a name and choose a type from the drop down. We name attributes the same way we name properties, in camelCase (the first letter of every word is capitalized except first word). By the way, you can NOT leave the type as undefined. You will get compiler errors.
NSUIntegers can be saved as any of the integer types. The number is just a matter of how large the range of values are. NSUIntegers would have the range of an Integer 32. Just keep in mind that all numbers are stored as NSNumbers. Binary Data for storing images, audio, etc. Transformable is for custom types and out of the scope of this post. The rest of the types are self explanatory.
So let’s add some properties:
Cool, so that was easy. But what about the owner property? How do we add that? It’s a Person object. Well, we start by making that Person entity into an Entity as well. So make a new entity and name it Person. Then give it a String attribute for Name. Now let’s go back to the Dog entity and make some magic.
Remember that table for Relationships? Well, that’s our other kind of property. Properties that are type of another entity are considered relationships instead of attributes. If you think about it … name, breed, and weight are all attributes of a dog but would owner be considered an attribute? Rather the dog’s owner is a relationship.
To add a relationship, either press the + button under the relationships table, or long press the Add Attribute button on the bottom right and click Add Relationship, or go to Editor > Add Relationship.
It’ll give you a default name. So put in “owner” for the name. The destination is pretty much asking what the type is for owner or in other words, which entity is being referred to as the “owner.” So of course, we’ll choose Person.
The last part is called Inverse which means the inverse relationship. The inverse relationship is pretty much the relationship from the other side’s point of view. So if the dog’s owner is a Person, then the inverse would be from the owners point of view: A person’s dog is the dog.
Notice how at the moment, the dropdown for Inverse has no options. That’s because we have to make the inverse relationship before we set it as an inverse. So we’ll go into the Person entity and add a dog Relationship which points to the Dog entity.
Notice how now the Inverse relationship has the option of owner. Choose that because the person is the person’s dog’s owner. Sounds gnarly but really isn’t that bad. Now when you go back to your Dog entity, it should have automatically selected dog as the inverse for owner. If it didn’t and it still says No Inverse, then you can manually select it.
We’re not done yet. If you think about it, our dog can have an owner, but our owner can have multiple dogs.
So our dog having one owner is a One to One relationship but our person having multiple dogs is a One to Many relationship. By default, our relationships are One to One. If you want to change it, while the relationship is selected, open up the Utilities panel on the right and click on the 3rd icon, the Data Model inspector. Go down to type and change the type to To Many.
Cool! So we successfully modeled our two entities. Now on to adding and saving.
Now to save our managed objects, we first have to have managed objects to save. So let’s make some. For sake of brevity, we won’t be covering subclassing NSManagedObject.
So, how do we make instances of our Entities?
Well, for the sake of simplicity, let’s work in our AppDelegate implementation inside the application:didFinishLoadingWithOptions.
Unlike instantiating regular objects, when we want to instantiate an Entity we make an instance of NSManagedObject. Instead of alloc and init’ing it, we will make a new instance using the entity’s Entity Description. We give it the entity name and which managed object context we want to put it in.
Now to set those attributes. Unfortunately, unlike other objects, we can’t use dot syntax with NSManagedObjects. If you want to use dot syntax, you’ll have to subclass it. To set the values for the attributes without having to make a subclass, use the setValue:forKey method.
So let’s set the values for those attributes. Let’s assume I made another entity for Person called shaggy.
Cool. So now in our application, we have a Dog managed object and a Person managed object. We inserted them into a Managed Object Context and as the name suggests, our Managed Objects are being managed by Core Data. Cool, so we’re good, right? Nope. If you close the app now and open it again, our two Managed Objects will be gone. They were in our context so what gives!? Well, we never saved the context. So now let’s get to the real question, how the hell do you save the context?
Yeah, that’s it. It’s as simple as that. We could go a little further, however. The save method returns a BOOL stating whether or not the save succeeded. We can use an if statement to log whether or not the save succeeded.
This can give tricky results since the save method fails if the context has no changes to save. Core Data doesn’t see the point of wasting it’s time writing the data to disk if there’s no change. So to be more accurate, we’ll nest this code in another if statement checking if there are changes in our context.
And voilà, we saved our objects. Now the next time we open our app, those objects will persist. Unfortunately, they’re not in our app … they’re in our storage. So now we need to figure out a way to grab the objects that were saved so that we can actually use them. Onwards to Fetching!
There are 3 ways to make Fetch Requests in code:
- The first way is to use to use the designated initializer and passing in the name of the entity
- The second way is to use a class method to return an instance of NSFetchRequest for the given entity name
- Lastly, we can do a regular alloc-init. This however is cumbersome since you’ll have to make a NSEntityDescription to pass in for the Fetch Request’s setEntity method.
You can set up a Fetch Request in the Data Model Editor as well by making a Fetch Request Template. We’ll look at that later.
Going back to our 3 fetch requests … No matter which one we use, we’ll get the same results. So, did we get the dog objects 3 times? No. We got them ZERO times. That’s because the NSFetchRequest is exactly what it sounds like, a request to fetch something. To actually fetch those things, you have to run the request or in this case execute.
The player of the Core Data Stack that will execute this Fetch Request is our Managed Object Context. We will be using the very straight forwardly name method: executeFetchRequest: error: … See? Straight forward. Since all the Fetch Requests are essentially the same, for the sake of simplicity we’ll use the first one.
Cool, so now we grabbed all the Dog entities in our Managed Object Context and put them in the array fetchedDogs. Ironic name, huh?
Well, that was how you fetch all Managed Objects with a certain Entity Description. Now let’s say we had a LOT of dogs in our database and we wanted to get Scooby Doo but we somehow forgot his name (How???). We know he’s a Great Dane. Is there any way we can only grab the Great Danes from our now Dog Database?
Well, yes. Enter Predicates. NSPredicates are useful little objects that allow you to filter a collection. I won’t be going through too much of how they work so feel free to read up on them before continuing.
So assuming you know how NSPredicates work, we will simply make a Predicate that filters based on the “breed” and checks for it to be “great dane” (Case insensitive). Lastly, we add it to the Fetch Request by using the setPredicate method.
Now, your Fetch Request will only fetch Great Danes.
Ok, so that’s great! So let’s say we got a clue now. We know his name starts with an S! … or maybe it was an D? Now in the case we fetch 100 Great Danes, it’s gonna be a real pain to go through them all. Wouldn’t it be great if we can sort them alphabetically so we can jump straight to the dogs with the names starting with D or S? Enter Sort Descriptors.
Once again, I won’t go into how Sort Descriptors work but assuming you know how (go read up on it), it’s as simple as the Predicate. You just make your Sort Descriptors and pass in an array of Sort Descriptors. Why an array? So you can have more specific sorting. For example, you can arrange all your Dogs by their breed and then sort all the Dogs of a certain breed by alphabetical order.
So, now we fetched all our Dog Managed Objects that are Great Danes and have them in Alphabetical order. Awesome!
Before we conclude this post, let’s see how we can use Fetch Request Templates to help us with cleaner code. As you can tell by the name, it’s a template from which you can make a Fetch Request.
So to make a Fetch Request Template, we start by going to our Data Model Editor. To actually add it, we can either long press the Add Entity button at the bottom and then click Add Fetch Request or we can go to Editor > Add Fetch Request.
So we start by give our template a name. Name it something descriptive so it’s easy to understand in the code. Now notice the area where it says Fetch all. Here we can select which entity we want to fetch. Notice the area underneath it. This is the predicate conditions area. We can add a new condition by pressing the + button on the right.
It’ll give you a 3-part sequence for the condition:
ATTIBUTE — OPERATOR — QUERY
So you would choose an operator (In this case, breed)
We would choose an operator (In this case, is)
And then we finish the expression (In this case, Great Dane)
Cool, so now we have our template. Now to actually make a Fetch Request from it, we go back to our code and we do this:
We use the Managed Object Model (not Context) method fetchRequestFromTemplateWithName:substitutionVariables: to make our Fetch Request. We just give in the template name and an empty dictionary for substitutionVariables since it can’t be nil. And we got our Predicate! As a bonus, the Predicates we made in the Data Model Editor are automatically added! Unfortunately we’ll still have to add Sort Descriptors the old fashion way (Let’s hope Apple adds this into the Editor eventually).
Now be careful, you can also use fetchRequestTemplateForName: as well, but it returns an immutable Fetch Request. What this means is that if you try to set the Sort Descriptor for a Fetch Request you get from this method, your project won’t compile and you’ll get this:
So feel free to use the shorter method if you don’t plan to use Sort Descriptors. Otherwise, stick to the longer method.
So that was how you use a Fetch Request Template. It can be useful for keeping your code cleaner. And with that, we are officially done with Fetching.
- We start with modeling by adding a Data Model file to our project
- We add Entities and give them attributes
- We set any relationships between the Entities
- Next we instantiate our Managed Objects
- To do so, we use the NSEntityDescription method insertNewObjectForEntityForName:inManagedObjectContext:
- After making and setting up our Managed Objects, we call save our Context by calling the NSManagedObjectContext method save
- Now when we want to get our Managed Objects out from the NSManagedObjectContext, we make a Fetch Request
- We can initialize it with the appropriate Entity name
- We can optionally add a Predicate and an array of Sort Descriptors
- To actually run the Fetch Request, we use the NSManagedObjectContext method executeFetchRequest:
- We can use the Data Model Editor to make a Fetch Request Template and use the fetchRequestFromTemplateWithName:substitutionVariables: to make the Fetch Request in code
And those we’re the basics of Core Data. Sorry for horribly the long post. Hopefully you got some value out of this.
From here, you might want to check out the post on Subclassing NSManagedObject.