How Did I Do That? (Part Two)

Continuing from yesterday..

Multiple XIBs

In my previous post, I mentioned that my application gives tasks a unique number so that I can easily reference them elsewhere, but that it might not be desirable to show this number at all times. In this situation, one can use a (subclass of) UITableViewCell and then when the cell is instantiated add a subview for the task number and move other fields accordingly to compensate. But I didn’t fancy programmatically adjusting such a view – the idea smelled bad. Instead I decided to create two XIBs and then choose between them when instantiating the cell. This is done as follows:

Create one XIB as normal, and a custom UITableViewCell subclass. In the XIB set the “Custom Class” field to the name of that subclass, and then create / synthesize IBOutlets and IBActions as normal. This is all standard stuff. In my app, I called the subclass TaskItemCell.

Duplicate the XIB, and add additional objects, adjusting (or removing) the existing ones as required. Create / synthesize IBOutlets and IBActions corresponding to these new objects. For my app, I named this XIB TaskItemCellWithID.xib.

At this stage, I had two XIBs which have the same custom class. Because this class has a set of properties that are common to both XIBs either one can be used. Here’s the method I use to populate the content of a cell, according to a specific task.

You’ll see that I don’t test which XIB is being used, because the class doesn’t care. In the UITableViewController‘s cellForRowAtIndexPath method, I merely check the user’s settings to determine which XIB to load:


Customising the Toolbar

View controllers that are managed by a navigation controller can set toolbar items for the view controller before it’s displayed or after it becomes visible. I wanted to have the ability to tab a “trash” icon and for completed tasks to be permanently deleted, however, I only wanted this icon to be displayed when viewing completed tasks. This helps ensure it’s a conscious action.

The method to establish the toolbar in my view controller draws the segmented control and the edit button (which is employed to allow tasks to be manually re-organised or individually deleted). Then, when the segmented control is changed, the corresponding method that responds to this change decides whether to insert the “trash” button.

UIBarItems include a tag property which allows applications to easily identify bar item objects. I use this to determine if the first item in the toolbar is the “trash” bar item or not, and add or remove it from the toolbar accordingly. Because I don’t care about any other tags in this toolbar, I’ve arbitrarily given it an NSInteger value of 10.


Action Sheets

Now that I had a settings panel and a trash button, I could implement deletion of completed tasks, and depending on a setting ask the user for confirmation.

The UIActionSheet is a view that (for iPhone applications) usually slides up from the bottom of the screen. After it is created, it can then be displayed relative to a toolbar or tab bar. For this application all I needed to do was ensure that the sheet was displayed in accordance with the user’s preference, and then delete the tasks.

Because I hooked up NSFetchedResultsController to respond to deletions, when the tasks are deleted the display updates automatically – there’s no need to reload the table.

Here are the three methods which handle deletion of completed tasks. I explicitly extracted the code that invokes the deletion just in case there are other actions to be taken in future (e.g. animating the trash icon, as per the Mail application).

How Did I Do That? (Part One)

Over recent days I’ve added a few features to my test app which now means I can use it on a regular basis. It’s no longer an exercise in learning, it’s something which is on my homescreen1. This post is the first of a two parter about some of those features.

The app, which I have named “Alisto” is simply a tool for keeping lists of lists. It was borne from a need to have something a little like Clear, but without the gimmicky colours and gestures.

The home page of the app gives me a list of lists, each of which has a badge to its right hand side showing how many incomplete items (tasks) I have in that list. It puzzles me that there doesn’t seem to be a class which generates such badges, so I looked to third party open source libraries. The one I chose is TDBadgeCell, which I subclassed and tweaked2. I need to refine the look of these badges some more to make them look perfect.

My general technique for working with UITableViewCell subclasses is to let instances draw themselves, with the owning controller simply passing in an object to be drawn. In this case I pass my List object. This keeps the view separate from the model, and allows the class to be easily reused elsewhere.

If I tap on a list, then the actual tasks on that list are displayed. When I started developing the application, I kept the complete and incomplete tasks on the same view, using a NSFetchResultsController to handle the fetching of the tasks from Core Data, and then tailoring the view of each cell according to the state of its task. I include a checkbox in each cell and overlay an invisible button so that I can quickly tap a task as complete or incomplete. This action then results in the task being updated in Core Data.

Now we get to some of the magic of NSFetchResultsController. Because it uses a protocol that allows receivers to respond to changes to the results set, the application redraws the cell that’s just changed its state. And the same part of the application can handle situations when such cells are created, deleted or moved.

This is particularly handy when it came to splitting the task list into two sections: one for incomplete tasks, the other for complete tasks. The toolbar at the bottom of the view has a UISegmentedControl, which when tapped fetches a new results set for NSFetchResultsController and then forces the table to reload. And, because of the aforementioned delegate, when a checkbox is tapped, the corresponding task disappears from the table on display.

You’ll see from the second image on this post that tasks have a number by them. This is merely a result of wanting to scratch my own itch, by having tasks that have a unique number so that I can easily reference them elsewhere. (Yes, this means that I can even use the app as a simple, personal Kanban system3) But I didn’t necessarily want them on display at all times. Which brings me onto settings..

Time was that applications took the easy route to settings by using the Foundation framework’s Settings bundle. This allows developers to specify a user interface for a settings page (or pages) via .plist file(s). The problem with this approach is that these settings are accessed via the Settings app, which means a user needs to jump out of an application to change its settings, and the application needs to respond to any changes when it’s reactivated.

So, I chose the more friendly approach of building settings into the application, hence the gear button at the top left corner of the home page. When tapped, this causes the application to present a modal view with (currently) two options.

This view is basically a static table, with pre-defined content. Only the status of the switches varies. Through Xcode’s UI builder, Apple provides a excellent way of creating static table, via the Storyboard facility. Unfortunately Storyboards are an all or nothing facility. If you want one in your app, your whole app needs to begin from a Storyboard, which is a little overkill for something like this, (and the jury is hung as to whether Storyboards are a good idea). So I needed some way of easily creating these two cells and writing the code to display and act upon their changes.

As it happens, you can create a table cell in a XIB file. Moreover, you can have as many different table cells in the same XIB file:

In the corresponding controller for the XIB, you create an IBOutlet for each cell, then in the cellForRowAtIndexPath method, return the particular cell for the requested row. The pertinent parts of the settings controller for Alisto are as follows:

Coming tomorrow:

  • Using multiple XIBs in a subclassed UITableCell;
  • Customising the navigation controller’s built-in toolbar;
  • Action sheets
  1. Despite the fact it still has no logo or launch screen.
  2. I’m very keen on subclassing UITableViewCell as you’ll discover during the next post.
  3. Which requires the app to allow moving of tasks between lists, as it does.

Tabs Gone Wrong

The iOS UITabBarController allows developers to easily provide a tabbed interface which allows the user to select between a number of different views. The controller can hold on display up to five different tabs, so when there are more options available applications typically have a “More..” tab in the fifth position that when selected links to additional views.

Applications which have this “More..” functionality, usually also have the ability to re-order tabs, and allow the user to decide which views should appear on the tabs.

Before I started to learn about iOS, I was under the impression that the “More..” functionality was something that had to be handled via code, but it turns out not to be the case. The “More..” tab is displayed automatically if there are six or more views given to a UITabBarController, and iOS presents the user with the other (missing) views when it’s selected. Furthermore, the re-ordering and editing of a tab bar is also something built into the system. Developers can decide which tabs can be edited or re-arranged.

All of which leads me to the sometimes puzzling development of side tab bars in applications. Sparrow was the first one I noticed using this technique of swiping views away to reveal a view selector (in Sparrow’s case, email Folders and Accounts). This I consider just suboptimal, because:

  • You cannot tell what other things you can view until you swipe away the current view;
  • The swipe action itself is more time consuming than simply clicking.

In my opinion, the best exponent of tab usage was version 2 of Remember The Milk. This venerable task management service displayed five tabs (chosen from a total of seven views), and you could organise it accordingly. I never used the default “Tomorrow” tab, so I replaced it with the “Search” tab. This gave me quick access to all lists that I used on a frequent basis, directly visible and immediately available for selection.

Now, however, probably for some kind of synergy with their iPad version, all of these tabs are now permanently hidden behind a swipe, first to reveal the ‘tabs’, then a tap or swipe to show the new view. I often kept the default “Lists” tab set to display one particular smart list. In previous versions this took me one tap. Now it takes me a swipe and a tap.

In the interests of making a user interface look distinctive and funky, there’s been a drop in usability, and that’s disappointing.