iOS Recipes - Matt Drance [38]
The only real value of the array in this example is to give us an abstracted row count. We can get that, as well as readable, flexible row indexes, by using enumerations. We start by enumerating all the sections we want. The first element is initialized to zero, which is the first valid section and row index in a table view.
OrganizedTableView/Classes/RootViewController.m
enum PRPTableSections {
PRPTableSectionFavorites = 0,
PRPTableSectionAlerts,
PRPTableNumSections,
};
Note that the final PRPTableNumSections value is not a section identifier. It’s a natural count of the sections in our table view, since it follows the last section. This is very convenient for ‑numberOfSectionsInTableView:.
OrganizedTableView/Classes/RootViewController.m
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return PRPTableNumSections;
}
We do the same for our table rows, declaring a separate enum for each section to ensure the indexes will be right. The system immediately begins to pay off when returning the number of rows in each section: we’ve eliminated the magic numbers and also made the code more readable for future maintenance.
OrganizedTableView/Classes/RootViewController.m
enum PRPFavoritesRows {
PRPTableSecFavoritesRowTeam = 0,
PRPTableSecFavoritesRowColor,
PRPTableSecFavoritesRowCity,
PRPTableSecFavoritesNumRows,
};
enum PRPAlertsRows {
PRPTableSecAlertsRowAlerts = 0,
PRPTableSecAlertsNumRows,
};
OrganizedTableView/Classes/RootViewController.m
switch (section) {
case PRPTableSectionFavorites:
return PRPTableSecFavoritesNumRows;
case PRPTableSectionAlerts:
return PRPTableSecAlertsNumRows;
default:
NSLog(@"Unexpected section (%d)", section);
break;
}
The ‑tableView:cellForRowAtIndexPath: method combines the enums and produces the appropriate content. It starts by checking the requested section against the PRPTableSections enum and then the row against the corresponding row enum for that section.
OrganizedTableView/Classes/RootViewController.m
switch (indexPath.section) {
case PRPTableSectionFavorites:
cell = [PRPBasicSettingsCell cellForTableView:tableView];
switch (indexPath.row) {
case PRPTableSecFavoritesRowTeam:
cell.textLabel.text = @"Favorite Team";
cell.detailTextLabel.text = @"Mets";
break;
case PRPTableSecFavoritesRowColor:
cell.textLabel.text = @"Favorite Color";
cell.detailTextLabel.text = @"Blue";
break;
case PRPTableSecFavoritesRowCity:
cell.textLabel.text = @"Favorite City";
cell.detailTextLabel.text = @"New York";
break;
default:
NSAssert1(NO, @"Unexpected row in Favorites section: %d",
indexPath.row);
break;
}
break;
OrganizedTableView/Classes/RootViewController.m
case PRPTableSectionAlerts:
switch (indexPath.row) {
case PRPTableSecAlertsRowAlerts: {
PRPSwitchSettingsCell *alertCell =
[PRPSwitchSettingsCell cellForTableView:tableView];
alertCell.textLabel.text = @"Alerts";
alertCell.cellSwitch.on = NO;
cell = alertCell;
}
break;
default:
NSAssert1(NO, @"Unexpected row in Alerts section: %d",
indexPath.row);
break;
}
break;
default:
NSAssert1(NO, @"Unexpected section (%d)", indexPath.section);
break;
Generating Static Table Cells
The OrganizedTableView project accompanying this recipe uses subclasses to obscure the standard table cell reuse mechanism. If your table view has a small number of cells, it may be more appropriate to simply store each individual cell in properties and avoid table cell reuse altogether. Review “The Technique for Static Row Content” in Apple’s Table View Programming Guide for iOS document before deciding how to store and generate your table cells.
So, our table has a structured, predictable, readable flow. Now let’s talk about those pesky design changes. Our Favorites section has three rows: Favorite Team, Color, and City. You decide that City should come before Color, not after. To solve this problem for the entire class, you