Document-based Dynamic Table Views


The iPhone application I’m developing uses a Property List (plist) as the fundamental data structure for all app content. The application’s job is to present the plist document to the user in an attractive format, and to allow editing of the document.

Apple has already solved this problem; the Settings Bundle in an iPhone application is a plist file. The Settings app built into the iPhone OS displays a hierarchy of views that allow you to view and edit this Settings Bundle. I imagine one could gain some good insight if Apple were to release the source code for the Settings.app, or a sample based on that application. Meanwhile, we are on our own.

When I first began thinking about a good design for this application I thought of XSL style sheets. An XSL style sheet turns an XML document into a visual representation, typically an HTML document rendered by a browser. I desired an analogous system for my app. The style sheet concept is an ideal worth striving for, but as a model it is slightly too simplistic because there’s no good equivalent to the browser in the analogy. So instead of translating the document into another document, we will translate the document into code that defines a view.

This conceptual model can be applied to any view, but I chose to use a hierarchy of table views because table views — especially the “grouped” style table view — provide a good basic structure to the view. A table view is comprised of an array of sections, and each section has an array of rows. I defined a TableSection class to represent a table section; the table view data source is an array of TableSection instances. For each UITableViewDelegate and UITableViewDatasource method that defines behavior for a specified section, we use the section argument to look up the corresponding TableSection instance, and delegate the implementation to that instance.

- (UITableViewCell *)tableView:(UITableView *)aTableView
         cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    TableSection* tableSection = [tableSections objectAtIndex:indexPath.section];
    return [tableSection tableView:aTableView cellForRow:indexPath.row];
}

The pattern is identical for methods such as numberOfRowsInSection, heightForRowAtIndexPath, canEditRowAtIndexPath, and so forth. Thus the behavior is in the hands of the TableSection (or derived class) instance. The instance holds a reference to the view controller and document, from which it can draw whatever data it needs, and to which it can write any changes it desires.

Not every UITableViewDelegate method fits nicely into this paradigm. For example, it is typically easier to implement the majority of didSelectRowAtIndexPath directly in the view controller class. To facilitate identification of the TableSection instance a user has selected, I added an integer tag property to TableSection, identical to the tag property in the UIView class.

With the combination of the delegation of some methods and use of the tag property in other methods, we now have a very flexible document-based view setup. The power of this setup became clear once I began developing a library of TableSection subclasses.

  • ButtonTableSection implements a basic clickable button. When the row is selected, it is treated as as a button-press. The action is implemented in the didSelectRowAtIndexPath method; the button may be identified by the section tag.
  • MultirowTableSection indexes into an array object in the document instead of of drawing data directly from root level of the document as the TableSection base class does.
  • CheckboxTableSection allows toggling of a set of non-exclusive boolean options in the document.
  • RadioTableSection allows setting a variable to one of several allowed values.

For the UITableViewDatasource delegate methods that define the appearance of a particular cell, the TableSection delegates the behavior yet again to a cell class, TableCell, derived from UITableViewCell. TableCell makes use of a technique described on the Llamagraphics blog that generalizes the logic for obtaining an instance of the cell class. TableCell also defines a method called setupCellForDocument that is responsible for configuring the cell instance with the data in the specified document.

Once I announce more details of my application I will post some screenshots. For now I hope other developers find this design inspires insight for your own document-based apps. I look forward to your feedback!

Posted in: Programming on January 14th by Ed


No comments yet

No comments yet.

RSS feed for comments on this post. TrackBack URL

Leave a comment