Tag Archives: NSFetchRequest

How to fetch multiple Entities with an NSFetchedResultsController

It’s easy to power a UITableView with Core Data, thanks to the NSFetchedResultsController. To display data, the latter needs an NSFetchRequest. This is great if you’re displaying the same entity over and over again in your table view.

By default and definition however, a fetch request can only ever fetch a single entity from our Core Data stack. What happens if you have two or more entities that you’d like to display in your table view? Technically we’d need multiple fetch requests for that, but how would we add all of them to the fetched results controller?

The answer is: we can’t!

But there is a workaround that may work for your project: we can make use of Entity Inheritance, which will allow us to fetch multiple entities with the same fetch request. This can be a useful timesaver. In this article I’ll explain how this works.

Entity Inheritance only makes sense if your entities are similar in structure. Imagine a flight tracking app in which you have two entities, one for incoming and one for departing flights. Both entities would perhaps have a flight number (NSString) and a time associated with them (NSDate).

 

Let’s build a project

To put this into practice, we can create one entity with these attributes, and then create a second empty entity that inherits from the first. Alternatively we can create one abstract entity with those attributes, and create two child entities that both inherit from the first – either approach will work fine. I’ll stick to the latter option for the remainder of this article.

Let’s create a new project based on the Master/Detail template and inspect the data model. It contains one Event entity that we’ll use. It already contains an NSDate attribute called timeStamp, and I’ll add another one called flightNumber (an NSString).

Screen Shot 2015-09-07 at 11.58.58

We will use this entity in our fetch request to show data in our table view, but we won’t create “events” as such to populate the app. We’ll do that with two new entities that shall be children of this parent entity. Let’s go and create those, and call them Inbound and Outbound. Leave them empty, but select Event as the parent entity on the right hand side (in the Data Model Inspector).

Screen Shot 2015-09-07 at 12.04.03

So far so good! To finish off the data model, let’s create managed object subclasses so we can work with them better in our code. Head over to Editor – Create NSManagedObject Subclass and select all three entities. Xcode is a bit buggy here: make sure you place them inside your project folder, Xcode will always volunteer the folder prior to that.

Screen Shot 2015-09-07 at 12.06.07

Notice also that Xcode will place your new files above the project in the navigator. Apple are good at changing stuff without notice, but they’re not so good at fixing things (as this example shows). Simply highlight the classes and drag them into your main project’s group. Your project navigator should look like this – just to avoid any nasty error messages down the line:

Screen Shot 2015-09-07 at 12.50.20

 

Coding the interface

I’m going to keep it super simple here and leave most of the code from the template as it is. I will however create two empty methods to insert an inbound and an outbound flight to the app. We already have a plus icon at the top right that will insert an Event item. We’ll use the same location to create an outbound flight, and on the left hand side we’ll add one to create an inbound flight.

Before we begin, we’ll import all necessary header files into MasterViewController.h:

In addition to our three generated subclasses I’m also importing AppDelegate.h so that I can call a convenient method that will save our managed object context for us.

Next, in the MasterViewController.m file, we’ll add two methods that will create a dummy object each and inter it into the managed object context.

 

When an object is created, it is populated with dummy values here: a date and time of “right now” and a simple title that shows what type of flight has been added. Obviously in a real app, this is where the actual data would be added. As soon as we save the context, our objects are stored (we’ll do that via the conveniently provided method in our AppDelegate).

We shall call the above methods with two buttons at the top left and right. Rather than add those with connections in the storyboard, we’ll do it like Apple did in the template and create those button objects in code. Apple does it in viewDidLoad, which currently looks like this:

 

 

I’ll remove the edit button on the left and replace it with my own instances, each of which will call the insert methods via a selector. Here’s the updated version for our demo app:

 

 

Displaying our data

Try running the app: it should work fine and insert a new timestamp with either button. But all we see is the date right now. Let’s fix this by entering our Main.storyboard. Find the table view cell, select it and change its style from Basic to Subtitle. This will display two lines of text. Feel free to change the word Master into something more appropriate (perhaps Flight Tracker).

Screen Shot 2015-09-07 at 12.53.17

Now we’ll head back to MasterViewController.m and populate those two lines properly. There’s a method called configureCell. It currently looks like this:

 

 

Let’s zoosh it up a bit and replace it with this:

 

And there we have it: both our entities are displayed in the same table view.

Result!

iOS Simulator Screen Shot 7 Sep 2015 13.02.41

 

Extra Credit: Tinting cells by testing the entity type

There’s just one more thing: we may want to set inbound and outbound flights apart visually by tinting the cell background depending on what type of entity is displayed. For example, inbound flights could be shown as green, while outbound flights could be shown in blue.

We can do this by testing which class the current Event object belongs to. Add this code to the bottom of the configureCell method we’ve seen above:

 

iOS Simulator Screen Shot 7 Sep 2015 18.00.39

And there we have it!

Entity Inheritance behaves much like Class Inheritance: whatever attributes the parent entity had, the children will inherit without us having to create the same attributes again. The same goes for any code we write in the parent subclass. Obviously Entity Inheritance only makes sense if your data is similar, as it is in the flight tracker example, or perhaps in a personnel database.

 

Demo Project

I’ve got a working demo project on GitHub. It’s a fully working version of what I’ve explained in this article. Feel free to examine it:

How to create a Fetched Results Controller

The NSFetchedResultsController makes populating UITableViews a breeze. I keep forgetting how to set those up, so here’s a quick list on how to create those:

  • create a Fetch Request
  • create the Fetched Results Controller with the Fetch Reuqest
  • execute the Fetch

The Fetch Request itself needs:

  • a Managed Object Model
  • an Entity Name (i.e. what to fetch)
  • an optional Template if created visually
  • an optional array of Sort Descriptors

Here’s a custom initialiser that first creates a Fetch Request, adds this to a Fetched Results Controller and finally executes the fetch.

How to create a Fetch Request in the Xcode Model Editor

You can create Fetch Requests in the Xcode model editor, including a Predicate. These are somewhat easier to setup. To create one, select your .xcdatamodeld file, then head over to Editor – Add Fetch Request. Give it a catchy name and a filter property, and much of the above code becomes obsolete.

Here’s how you can retrieve one of those in code:

Note that to retrieve your Fetch Request Template you need a reference to your Managed Object Model as well as your context. The easiest way to grab hold of it in an iOS app is to pass it in on a property, just like we did with self.managedoObjectContext.

How to retrieve a Managed Object in Core Data Fetch Requests

Retrieving Managed Objects is somewhat more complex than creating them, mainly because you can filter what you’re getting back rather than retrieve everything that your store file has to offer.

Let’s first illustrate a basic NSFetchRequest. For the following examples I’m using the iOS Master/Detail template which provides an Entity called Event with a property called timeStamp. I’ve created custom subclasses for this entity. Press the add button a few times so we have some data, then quit the application.

Basic Fetch Request

Here’s how we can retrieve all our values using a basic Fetch Request:

This content is for members only.