Custom UITableViewCell from Xib with ease

grab the source eppz!cell at

As it is common among these articles, the main point is always to keep the client code clean, resulting in some reusable, extendable class for everyday use. This article will just do the same. Ending up in a custom TechCrunch themed table with instantiating each UITableViewCell from Xib file, with a lovely one-liner hook towards the clients. I’ve found a public FeedBurner feed of the recent TechCrunch articles, hence the theme inspiration.

Custom UITableViewCell from Xib with ease - Ending up in a custom TechCrunch themed table with instantiating each UITableViewCell from Xib file.

Having some well designed base class, the custom UITableViewCell from Xib implementation can free of any boilerplate code focusing only on design details.

-(UITableViewCell*)tableView:(UITableView*) tableView cellForRowAtIndexPath:(NSIndexPath*) indexPath
{
    return [TCItemCell cellForTableView:tableView
                          atIndexPath:indexPath
                      withModelSource:self];
}

As you can see, all the instantiating, dequeue/reuse code, and configuring with model object is encapsulated within the actual UITableViewCell subclass. It uses a base class EPPZTableViewCell:NSObject to be introduced soon below, then extending it by adding some concrete features of the TechCrunch themed custom UITableViewCell.

As this post is a subject of some public curiosity, I think I’m gonna create a Drop-in UITableViewCell from Xib snippet with three files of this method, with some few seconds tutorial on usage. If you think you gonna use it, please donate the project by following eppz! on Twitter to encourage development. You’re great at reading this, thanks there.

1. The base class (embodies loading UITableViewCell from Xib)

You can find a pretty convenient method for instantiating view’s from xib files in another article – 5 approach to load UIView from Xib – around here, so the base class for the cells will just use the same method. Thus, EPPZTableViewCellOwner:NSObject class has the sole purpose of maintain a reference for the cells among freshly instantiated Xib content, in other words to keep the role of File’s Owner in the custom UITableViewCell Xib file.

This utility class shows it’s real advantages when you store multiply custom views in a single Xib file, like some alterations of UITableViewCells along with some customized section headers for example. Now it stands here to make the code more explicit.

@interface EPPZTableViewCellOwner : NSObject
@property (nonatomic, weak) IBOutlet EPPZTableViewCell *cell;
+(id)ownerWithNibName:(NSString*) nibName;
@end

@implementation EPPZTableViewCellOwner
+(id)ownerWithNibName:(NSString*) nibName
{
    EPPZTableViewCellOwner *instance = [EPPZTableViewCellOwner new];
    [[NSBundle mainBundle] loadNibNamed:nibName owner:instance options:nil];
    return instance;
}
@end

It has a factory method ownerWithNibName: that creates an owner instance, then loads the given Xib content (that will hook up references defined in Interface Builder to the owner immediately). After that, we can easily access the cell later on.

I’m going to introduce the cell base class EPPZTableViewCell:UITableViewCell implementation in a few graduated step for easier understanding. It also begins with a factory method, that creates a cell that can be passed back to the table, and invokes a cell configuring method configureWithModel: that concrete themed subclasses can implement later on.

@implementation EPPZTableViewCell

+(EPPZTableViewCell*)cellForTableView:(UITableView*) tableView
                          atIndexPath:(NSIndexPath*) indexPath
                      withModelSource:(id) modelSource
{
    //Create cell.
    EPPZTableViewCell *cell;
    EPPZTableViewCellOwner *owner = [EPPZTableViewCellOwner ownerWithNibName:NSStringFromClass(self)];
    cell = owner.cell;

    //Configure cell.
    id model = [modelSource modelForIndexPath:indexPath];
    [cell configureWithModel:model];

    return cell;
}

-(void)configureWithModel:(id) model
{ /* Subclass template. */ }

@end

At the configuring section it uses a protocol EPPZTableViewCellModelSource to proclaim a need for a model object for a particular NSIndexPath, it is nearly the same way that UITableView applies in it’s UITableViewDataSource protocol.

@protocol EPPZTableViewCellModelSource
-(id)modelForIndexPath:(NSIndexPath*) indexPath;
@end

You can implement this protocol right in you model classes, or simply in the controller code, like you usually do with all the other UITableView delegate methods.

The next step is to incorporate cell reusing. Actually this is the main reason this class method needs a reference to the table.

@implementation EPPZTableViewCell

+(NSString*)reuseIdentifier { return NSStringFromClass(self); }
-(NSString*)reuseIdentifier { return NSStringFromClass(self.class); }

+(EPPZTableViewCell*)cellForTableView:(UITableView*) tableView
                          atIndexPath:(NSIndexPath*) indexPath
                      withModelSource:(id) modelSource
{
    EPPZTableViewCell *cell;

    //Get a cell instance (either dequeue from tableView or allocate a new one).
    cell = [tableView dequeueReusableCellWithIdentifier:[self reuseIdentifier]];
    if (cell == nil)
    {
        EPPZTableViewCellOwner *owner = [EPPZTableViewCellOwner ownerWithNibName:NSStringFromClass(self)];
        cell = owner.cell;
    }

    //Configure cell.
    id model = [modelSource modelForIndexPath:indexPath];
    [cell configureWithModel:model];

    return cell;
}

-(void)configureWithModel:(id) model
{ /* Subclass template. */ }

@end

Nothing too difficult in implementation, just uses the well designed framework methods to see if there is any reusable cell, or we have to allocate a new instance. The main thing is that we have all this encapsulated in this base class, so these codes will never litter around any subclass or controller code anymore. It uses the class name as the reuse identifier, supposing you’ll create subclasses for concrete UITableViewCell implementation, which seems a reasonable assumption.

There is a tiny issue that can be moved into this class, namely providing cell height information. I do it with simply measure the actual view in one of the instantiated cells. So it is reasonable to create a second class method heightForTableView:atIndexPath: by which you can expose cell height information towards the clients.

To sum up EPPZTabelViewCell:UITableViewCell so far, you can inspect the code at GitHub to see the skinny interface, and the implementation .m file with all the details discussed above. I moved down the EPPZTableViewCellOwner:NSObject class to the entirely to remove annoying parts from the header file.

See EPPZTableViewCell.h at
See EPPZTableViewCell.m at

This may seem a bit overhead in terms of code lines, but this base class have to be written once, and you’ll never have to scatter around your controller implementation with these boilerplate stuff.

Anyway, the real thing just comes after, when you put this class to work, and start implementing a concrete subclass of it.

2. A concrete EPPZTableViewCell subclass (the customizing part)

As I told before, I simply want to create a really basic fronted for the TechCrunch feed (a simple JSON with predefined keys), with some colored labels, custom fonts. The result will look like this one below. I borrowed some UI details right from TechCrunch site, like colors, the Interstate typeface, and some heading style.

Custom UITAbleViewCell from Xib with ease - I simply want to create a really basic fronted for the TechCrunch feed (a simple JSON with predefined keys), with some colored labels, custom fonts.

I borrowed some UI details right from TechCrunch site, like colors, the Interstate typeface, and some heading style.

Let’s create a subclass of EPPZTableViewCell for this particular cell type, called TCItemCell:EPPZTableViewCell. It does nothing special beside inherit all the cool features from EPPZTableViewCell, and declares the label outlets that needs to be configured.

@interface TCItemCell : EPPZTableViewCell

@property (nonatomic, weak) IBOutlet UILabel *titleLabel;
@property (nonatomic, weak) IBOutlet UILabel *categoriesLabel;
@property (nonatomic, weak) IBOutlet UILabel *authorLabel;
@property (nonatomic, weak) IBOutlet UILabel *dateLabel;

@end

Since we have put the more generic logic into the superclass, the implementation part needs to implement only one (!) method, the configuring template configureWithModel: that we have defined before. This part contains the most specific, concrete pieces.

@implementation TCItemCell

-(void)configureWithModel:(id) model
{
    //Apply typeface.
    self.categoriesLabel.font = [UIFont fontWithName:@"Interstate" size:self.categoriesLabel.font.pointSize];
    self.titleLabel.font = [UIFont fontWithName:@"Interstate-Bold" size:self.titleLabel.font.pointSize];
    self.authorLabel.font = [UIFont fontWithName:@"Interstate" size:self.authorLabel.font.pointSize];
    self.dateLabel.font = [UIFont fontWithName:@"Interstate" size:self.dateLabel.font.pointSize];

    //Add, format content.
    self.categoriesLabel.text = [[[model valueForKey:@"categories"] componentsJoinedByString:@", "] uppercaseString];
    self.titleLabel.text = [model valueForKey:@"title"];
    self.authorLabel.text = [[model valueForKey:@"author"] uppercaseString];

    //Formatting date.
    NSDateFormatter *dateFormatter = [NSDateFormatter new];
    dateFormatter.dateStyle = NSDateFormatterFullStyle;
    NSDate *publishedDate = [NSDate dateWithTimeIntervalSince1970:[[model valueForKey:@"published"] floatValue]];
    NSString *dateString = [dateFormatter stringFromDate:publishedDate];
    self.dateLabel.text = dateString;
}

@end

There is some hassle around the typefaces and the date formatting, but this class is just the right place to implement such specific UI details, far from the controller code, far from the table.

If you would roll with some explicit model objects, you could simply cast it here to the given type, then configure the UI with that. Now we are going with this really loosely typed way, which I really consider error-prone, but for the sake of clarity it will do the job for now.

In the interface builder file everything happens you would expect, with the only constrain that you have to be aware of the File’s Owner type.

Custom UITableViewCell from Xib with ease - You simply set the File's Owner type to EPPZTableViewCellOwner.

You simply set the File’s Owner type to EPPZTableViewCellOwner, and hook up it’s cell reference to the actual UITableView cell on the stage. This makes the encapsulated instantiation possible.

Custom UITableViewCell from Xib with ease - Also you have to set the custom class TCItemCell we've made before to the UITableViewCell.

Also you have to set the custom class TCItemCell we’ve made before to the UITableViewCell.

Custom UITableViewCell from Xib with ease - The rest just straightforward, just hook up the corresponding labels to the IBOutlets you've defined in TCItemCell.

The rest just straightforward, just hook up the corresponding labels to the IBOutlets you’ve defined in TCItemCell.

So the custom UITableViewCell is ready, and longing for get instantiated from it’s carefully designed Xib file.

3. The controller code (put our custom UITableViewCell from Xib in use)

Controller code is just basically the same like any other UITableView implementation. Forgive me that the loading process is a bit rough (using AFNetworking’s lovely asynchronous JSON loader), simply fetches the whole JSON without any particular UX towards the user, but designing such experiences is out of the current focus. Also I don’t like to use direct strings as keys/keyPaths to reach data within a model collection, as I mentioned before.

static NSString *const _feedUrl = @"http://ajax.googleapis.com/ajax/services/feed/load?v=1.0&num=10&q=http://feeds.feedburner.com/TechCrunch/";

@interface EPPZViewController ()
@property (nonatomic, weak) IBOutlet UITableView *tableView;
@property (nonatomic, strong) NSDictionary *feed;
@end

@implementation EPPZViewController

#pragma mark - Load the feed content

-(void)viewDidAppear:(BOOL) animated
{
    [super viewDidAppear:animated];

    //Get feed, refresh table on completition.
    [[AFJSONRequestOperation JSONRequestOperationWithRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:_feedUrl]] success:^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON)
    {
        self.feed = JSON;
        [self.tableView reloadData];
    } failure:nil] start];
}

#pragma mark - Populate table

-(NSInteger)tableView:(UITableView*) tableView numberOfRowsInSection:(NSInteger) section
{ return [[self.feed valueForKey:@"responseData.feed.entries"] count]; }

//Ask for cell height trough the smart class method.
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath*) indexPath
{ return [TCItemCell heightForTableView:tableView atIndexPath:(NSIndexPath*) indexPath]; }

//Implement the  protocol for the cell.
-(id)modelForIndexPath:(NSIndexPath*) indexPath
{ return [[self.feed valueForKey:@"responseData.feed.entries"] objectAtIndex:indexPath.row]; }

//And hook the cells up to the table with this promising one-liner.
-(UITableViewCell*)tableView:(UITableView*) tableView cellForRowAtIndexPath:(NSIndexPath*) indexPath
{
    return [TCItemCell cellForTableView:tableView
                          atIndexPath:indexPath
                      withModelSource:self]; //Tell that this controller provides the data for the cell.
}

@end

The interesting part is the Populate table section. The first method is straightforward, the usual tableView:numberOfRowsInSection: cell counter. The second method is uses the class method heightForTableView:atIndexPath: we declared in EPPZTableViewCell before. The third method provides the data/model source for each cell, trough the <EPPZTableViewCellModelSource> protocol we created for this purpose. And my personal favorite, the fourth method provides a fully configured cell to the corresponding <UITableViewDelegate> method with a single innocent line of code.

see the whole project eppz!cell at

If you feel a bit mixed up among the redirections incorporated here, just take a look at the prototype project eppz!cell at GitHub created for this article, and see the classes working together, which is actually more understandable than those features flattened out into this article.

The base class EPPZTableViewCell is just a clean design as a starting point to create your own UITableViewCell from Xib workflow. In some project there could be some more abstraction layers where you create more generic UITableView controllers, generic models, and factories that provides many different types of properly configured UITableViewCells for your tables, but that is more of a matter of the whole application code design than to fit into this article (it would be great to do anyway).

DISCLAIMER. THE INFORMATION ON THIS BLOG (INCLUDING BUT NOT LIMITED TO ARTICLES, IMAGES, CODE SNIPPETS, SOURCE CODES, EXAMPLE PROJECTS, ETC.) IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE INFORMATION ON THIS BLOG (INCLUDING BUT NOT LIMITED TO ARTICLES, IMAGES, CODE SNIPPETS, SOURCE CODES, EXAMPLE PROJECTS, ETC.).