The iOS framework that grows only as fast as its documentation
Table Cell Factory

Classes

class  NICellFactory
 A simple factory for creating table view cells from objects. More...
 
protocol  <NICellObject>
 The protocol for an object that can be used in the NICellFactory. More...
 
protocol  <NINibCellObject>
 The protocol for an object that can be used in the NICellFactory with Interface Builder nibs. More...
 
protocol  <NICell>
 The protocol for a cell created in the NICellFactory. More...
 

Overview

A table cell factory automatically creates UITableViewCells from objects.

The Nimbus table cell factory works by requiring that objects implement a basic protocol, NICellObject, which sets up a binding from the object to a specific cell implementation. This cell implementation can optionally implement the NICell protocol. In practice this is nearly always the case. You then simply use the factory in your table's data source and the factory will handle the rest. This allows you to completely separate presentation from data in your table view controllers.

A Simple Example: A Twitter Application

Let's say you want to build a Twitter news feed. We'll assume you've already figured out the network requests and now have individual tweets itching to be displayed. To use the Nimbus factory you will need two different classes: one for the tweet object and its data, and another for the tweet table view cell. Let's call them Tweet and TweetCell, respectively. You may even already have a Tweet object.

Implement the NICellObject Protocol

You must first implement the NICellObject protocol in your Tweet object. We want to link the TweetCell table view cell to the Tweet object so that the factory can create a TweetCell when it needs to present the Tweet object.

@interface Tweet : NSObject <NICellObject> {
// ...
}
@end
@implementation Tweet
- (Class)cellClass {
return [TweetCell class];
}
@end

Now that we've pointed the Tweet object to the TweetCell class, let's make the table controller use the NICellFactory.

Using the Factory

There are a few ways you can use the factory in your code. We'll walk through increasingly Nimbus-like implementations, starting with a vanilla UIKit implementation.

The following vanilla UIKit implementation has the advantage of allowing you to use NICellFactory in your existing code base without requiring a full rewrite of your data source. If you are attempting to switch to a pure Nimbus implementation using the cell factory then this is a good first step because it is the least invasive.

- (UITableViewCell *)tableView: (UITableView *)tableView
cellForRowAtIndexPath: (NSIndexPath *)indexPath {
// Note: You must fetch the object at this index path somehow. The objectAtIndexPath:
// is simply an example; replace it with your own implementation.
id object = [self objectAtIndexPath:indexPath];
UITableViewCell* cell = [NICellFactory tableViewModel:nil cellForTableView:tableView atIndexPath:indexPath withObject:object];
if (nil == cell) {
// Here would be whatever code you were originally using to create cells. nil is only returned
// when the factory wasn't able to create a cell, likely due to the NICellObject protocol
// not being implemented for the given object. As you implement these protocols on
// more objects the factory will automatically start returning the correct cells
// and you can start removing this special-case logic.
}
return cell;
}

This next implementation is what your vanilla data source implementation would look like once you have no more custom cell creation code.

- (UITableViewCell *)tableView: (UITableView *)tableView
cellForRowAtIndexPath: (NSIndexPath *)indexPath {
// Note: You must fetch the object at this index path somehow. The objectAtIndexPath:
// is simply an example; replace it with your own implementation.
id object = [self objectAtIndexPath:indexPath];
// Only use the factory to create cells now that every object used in this controller
// implements the factory protocols.
return [NICellFactory tableViewModel:nil cellForTableView:tableView atIndexPath:indexPath withObject:object];
}

If you are using Nimbus models then your code gets even simpler because the object is passed to your model delegate method.

- (UITableViewCell *)tableViewModel: (NITableViewModel *)tableViewModel
cellForTableView: (UITableView *)tableView
atIndexPath: (NSIndexPath *)indexPath
withObject: (id)object {
// The model gives us the object, making this much simpler and likely more efficient than the vanilla UIKit implementation.
return [NICellFactory tableViewModel:tableViewModel cellForTableView:tableView atIndexPath:indexPath withObject:object];
}

And finally, if you require no custom code in your model delegate, the above example can be shortened to a one-liner when you initialize the model:

// This is functionally identical to implementing the delegate in this controller and simply
// calling the factory method.
_model.delegate = (id)[NICellFactory class];

Customizing the Cell

We want to customize the cells as they are presented, otherwise all of the cells will look the same. After our TweetCell object is created in the factory, the factory will call the shouldUpdateCellWithObject: method on the cell, if it is implemented. Remember that cells are reused in table views and that any modification you may make to the cell could still be present the next time this cell is updated with an object.

- (BOOL)shouldUpdateCellWithObject:(id)object {
// We can be rest assured that `object` is a Tweet object because that's how we set up
// the bindings. If more than one type of object maps to this cell class then we'd have
// to check the object type accordingly.
Tweet* tweet = object;
self.textLabel.text = tweet.text;
// Returning YES or NO here is intended purely for subclassing purposes. Returning YES means
// that the object changed the cell in some way.
return YES;
}

Conclusions

The Nimbus cell factory can greatly reduce the amount of code you have to write in your table controllers while separating the data from the presentation. You can slowly ease yourself into using the factory if you already have a large existing code base.

If you are migrating from Three20, you will find that Nimbus' table factory is very similar to TTTableViewController, though greatly simplified and decoupled from the rest of the Three20 ecosystem. Where Three20 provided a tightly integrated solution, Nimbus allows you to plug in the factory where it makes sense.