Online Book Reader

Home Category

iOS Recipes - Matt Drance [33]

By Root 207 0
configured the cell yet! When reusing a cell, how do we get at those now-anonymous subviews that were added during creation? We have two options: set tag literals on the subviews, which we then use to fish them back out at reuse time; or write a UITableViewCell subclass with explicit properties. Going the subclass route is much more attractive because it does the following:

Defines a contract (properties) for accessing the subviews

Avoids the danger of tag collisions in the cell hierarchy (multiple subviews with the same tag)

Decouples the cell’s layout from the view controller, enabling code reuse across views and projects

By using a subclass, we get a number of other opportunities to simplify the table-building process. Every table view data source inevitably has the same cell dequeue/alloc code in it. This code is not just redundant; it’s also fragile: a misspelled cell identifier, a single instead of a double equals in our nil check—subtle errors lead to performance hits and wasted debugging time. If we didn’t have to constantly copy and paste this redundant code, or even look at it, our routine for building table views would be much less tedious.

Enter PRPSmartTableViewCell: a foundational subclass of UITableViewCell that eliminates clutter in our table view controllers and prevents costly bugs in our scattered cell boilerplate. The class’s primary task is to abstract away that boilerplate so that, ideally, we never have to worry about it again. The class has a special initializer method and two convenience methods, which we’ll explore next.

SmarterTableCells/Classes/PRPSmartTableViewCell.h

@interface PRPSmartTableViewCell : UITableViewCell {}

+ (id)cellForTableView:(UITableView *)tableView;

+ (NSString *)cellIdentifier;

- (id)initWithCellIdentifier:(NSString *)cellID;

@end

The +cellForTableView: class method handles cell reuse for a table view that’s passed by the caller—our table view controller.

SmarterTableCells/Classes/PRPSmartTableViewCell.m

+ (id)cellForTableView:(UITableView *)tableView {

NSString *cellID = [self cellIdentifier];

UITableViewCell *cell = [tableView

dequeueReusableCellWithIdentifier:cellID];

if (cell == nil) {

cell = [[[self alloc] initWithCellIdentifier:cellID] autorelease];

}

return cell;

}

This code should look familiar: it’s nearly identical to the reuse code you’ve surely written dozens (if not hundreds) of times as an iOS developer. Note, however, that the cell identifier string is obtained from another class method: +cellIdentifier. This method uses the cell’s class name as the identifier by default, even for subclasses of PRPSmartTableViewCell you write. Now, whenever we decide to write a custom cell class, we’re guaranteed a unique cell identifier for free. Note that the identifier is not marked static as you’ve seen in most sample code, so there is some extra allocation going on in the default implementation. If you find this to be a problem, you can always override (or edit) +cellIdentifier to change its behavior.

SmarterTableCells/Classes/PRPSmartTableViewCell.m

+ (NSString *)cellIdentifier {

return NSStringFromClass([self class]);

}

Finally, we use a new designated initializer, ‑initWithCellIdentifier:, to set up the cell and its layout. This is where we’d put the verbose layout code that would otherwise live in our controller.

SmarterTableCells/Classes/PRPSmartTableViewCell.m

- (id)initWithCellIdentifier:(NSString *)cellID {

return [self initWithStyle:UITableViewCellStyleSubtitle

reuseIdentifier:cellID];

}

With this new pattern, here’s how we’d write and use our table cell subclass:

Create a subclass of PRPSmartTableViewCell.

Override ‑initWithCellIdentifier:.

Call +cellForTableView: from our table view controller.

Now let’s take a look at our table view controller code for producing a custom PRPSmartTableViewCell:

SmarterTableCells/Classes/PRPRainbowTableViewController.m

- (UITableViewCell *)tableView:(UITableView *)tableView

cellForRowAtIndexPath:(NSIndexPath *)indexPath {

PRPDoubleRainbowCell *cell

Return Main Page Previous Page Next Page

®Online Book Reader