Tag Archives: UITableView

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 create a searchable UITableView (2014)

In this course I will show you how to create a searchable table view in Xcode 5.1 and iOS 7. The app will also be compatible with iOS 6.

There are six parts in total:

  • Part 1: an overview of what we’d like to achieve
  • Part 2: we’ll build the table view and populate it with dummy data
  • Part 3: hooking up the UISearchDisplayController
  • Part 4: displaying search results
  • Part 5: hiding the UISearchBar when the app launches (and activating it with a button)
  • Part 6: hiding the search bar in iOS 6

The whole course is about one hour in total. Enjoy!

Part 1: Overview

Continue reading

How to attach custom actions to an Edit Button Item (or The Dark Secrets of the Edit/Done Button)

You can create an editButtonItem in a UITableViewController like this:

If your view controller is embedded into a navigation controller, an edit/done button will show up and you can toggle its state by pressing it.

Edit-Done

That’s great, but it takes a deeper understanding of how this happens to make full use of it in your own projects.

What this button actually does is set the “editing” property of your view controller to YES or NO. If it’s YES, the button turns into “Done” (and equivalent translations), and if it’s NO then it turns into “Edit”. You won’t notice this on a standard view controller, but on derivatives (such as a UITableViewController) this has a substantial effect: the table view enters edit mode and changes appearance.

You can therefore test the state of the button by querying your view controller:

But that’s not an action, that’s just a test. If you’d like for something to happen when that edit button is pressed, you must override the following function which is called every time that button is pressed:

This method is called by the table view when that button is pressed. We’re calling the super method first, then add our own bits at the end. You can also call this method from anywhere and put the table view into or out of edit mode like so:

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

[emember_protected]

We also need to add the following method. This is mandatory for our reorder controls to show up.

Since we’re using Core Data, we don’t really want to update the table view directly – we want to leave that to the NSFetchedResultsController. To do this we need to conform to the NSFetchedResultsControllerDelegate protocol in our header file:

and implement te following method:

[/emember_protected]

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 add touch events to a UITableViewFooter (or header)

Table View headers or footers can’t be tapped. Sometimes however that’s exactly what we want to do.

In this example we’ll add a new UIView to out table view and add it to the table’s footer. Inside this view we’ll have a custom button which we’ll create with an image. We’ll also have a method that is called when the user presses the button:

The result is a row at the bottom of the table view which stays in place even if the table is scrolled – ideal of anything users should see at all times.

You can do the same for table view headers, just add the code to the “headerInSeaction” variants of the methods above.

Example of a tappable footer image/button
Example of a tappable footer image/button