Tag Archives: NSFetchedResultsController

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 implement Table Headers with NSFetchedResultsController in Core Data

iOS Simulator Screen Shot 28 Aug 2015 15.48.03To use sections in a table view that’s powered by Core Data and a fetched results controller, we need to specify a property called sectionNameKeyPath. It’s the key to making those header titles show up. Reading Apple’s ever so colourful documentation however doesn’t give us a clue what this means in human terms.

Here’s how to implement those with a simple example.

Starting out from the Master/Detail template in Xcode, create a new project and choose Core Data. This will setup the fetched results controller along with the rest of the Core Data stack. We’ll also get one handy Event entity with a single attribute: an NSDate called timeStamp. Run the app, click the plus button at the top and we’ll see a new date is inserted into the table.

But the table has no sections. Let’s assume we’d like to create a new section for every minute that has been logged in the database. So 18:07 would have a section, 18:08, and whatever else is available.

Creating Managed Object Subclasses

First we’ll create a managed object subclass from our model so that we can write some code for this. Choose the .xcdatamodeld file in Xcode and select Editor – Create NSManagedObject Subclass. Stash the two resulting files in your project folder.

In Event.h, add another property. It won’t be saved, it’ll be calculated on the fly. We already have the timeStamp property for the date object, so let’s call the new property minuteSection. Here’s the Even.h file:

In the Event.m file we’ll create a custom initialiser, which will turn our timeStamp into time string. Since this is a Core Data property we’ll have to mark it as dynamic, much like all the other Core Data properties in managed object subclasses:

Here we use an NSDateFormatter that turns the long date object into something like 18:07. Every event in our database logged at 18:07 for example will get its own section with that title.

Tweaking the Fetched Results Controller

Next, let’s turn our attention to the NSFetchedResultsController. In the Xcode template it’s in MasterViewController.m. There’s a custom initialiser with a method that by default looks like this:

Take a look at the sectionNameKeyPath property here: it’s set to nil, meaning we’re not displaying any sections. To tell the controller which property we want to use as section criteria, all we have to do is provide the string of the property we’d like to use. In our case, that’s minuteSection. Quick modification:

I’ve also taken the liberty to remove the cache and set it to nil, we don’t really need it here.

Showing the Section Titles

Right now the app will run as usual, but we still won’t see any new sections. Even though they are displayed, we don’t see them separated from the cells. What we need to do is add a method to our table view delegate and make those sections show up with the right titles.

In MasterViewController.m, hunt for a pragma mark called Table View. You’ll find methods to show how many rows and sections there are, both of which are being read from the fetched results controller. Examine the code to spot some similarities to what we’re doing next.

Add a method called titleForHeaderInSection, it comes up as part of the automatic code completion as soon as you type “- table” (it’s a long list). Here’s what we need to add to it for those section headers to show up:

It’s only two lines of code, but they’re rather long. Here we grab the controller’s current section and call it’s name method, which returns the string we’re looking for (i.e. 18:07, the hour and minute we’d like to use).

Run the app and add a few values to it. On every new minute, a new section is created. When you remove values, empty sections are automatically removed as well.

Further Reading

Demo Project

I’ve got a working demo project on GitHub – feel free to check it out:

iOS Simulator Screen Shot 28 Aug 2015 15.48.03

How to reorder a UITableView with Core Data

You’d imagine something as sophisticated as an NSFetchedResultsController has a built-in mechanism to let the user re-order cells arbitrarily. But that’s not the case, so we need to be inventive.

A table view can be re-ordered without problems, but how do we make the new order persist in Core Data? Looks like our managed objects need an integer property for that. In this example I’ll use a 16 bit integer called position – but you can call it anything you like.

There are several (more or less) complicated approaches to the rest of this puzzle. I will use Matt Long’s excellent and least complicated option by adding all fetched objects to an array. Let’s do this step by step, starting with the Xcode Master/Detail template. My managed object is called Phrase.

First we need to make sure our table view is reorder-able. Let’s do this by implementing

This content is for members only.

This is called automatically if the fetched results controller has noticed a change in its data structure. It grabs its new objects and refreshes the table view – and we’re done.

Here’s a full working project that implements this feature among other things:

How to return the section title in a UITableView with Core Data

Our NSFetchedResultsController can take care of this too:

First we determine if we have sections at all, and if we do we return their respective titles.

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 return the number of rows in a UITableView with Core Data

Likewise, here’s how we return the number of rows using a fetched results controller – as provided by the Master / Detail template: