RCBlockedCell: Putting UITableViewCell definition and action together with blocks

Problem

I've been recently been working with the UITableView and UITableViewController subclasses. It is an annoyance to maintain two methods that will define what will show up in the table cell and what happens if that table cell is selected.

Imagine having more 10 cells with varying behavior per cell. OK, you coded that. Now, you have to rearrange the order of the cells. Of course, you can use an enum but still, you have to look at two places to determine how the cell is defined and what happens if it is selected. You're gonna have to keep your tableView:cellForRowAtIndexPath: and tableView:didSelectRowAtIndexPath: methods in sync all the time.

My Solution

Yeah, let me emphasize on the My. If you have a better way, I'd want to hear about it. Or if you think you can improve this, visit the repo and fork it, sister ;) So I thought about making the action on cell selection be an attribute of the cell since an action is linked to the cell that is being selected anyway. However, I needed a table view controller subclass which you should also subclass for convenience to complete the cell block attribute chain. 

You can find it on the .

How to Use

You're probably here from the GitHub repo trying to find out how to use this cell. It's pretty straight forward.

  1. Instead of subclassing UITableViewController, subclass RCBlockedTabelController instead. It's a very thin layer over UITableViewController.
  2. In your table view controller, use RCBlockedCell instead of UITableViewCell and simply...
  3. Define what happens when the cell is selected by defining a block the follows the RCDidSelectBlock type and assign it to rcblockedCell.didSelectBlock. This block will be invoked when the cell is selected.
  4. Optionally, set rcblockedCell.shouldDeselect to NO if you don't want the cell to deselect itself after being selected.

Example

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *reuseID = @"RCBlockedCellID";
    RCBlockedCell *cell = [[RCBlockedCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:reuseID];
    __unsafe_unretained RCBlockedCell *cellWeak = cell;
    cell.didSelectBlock = ^(NSIndexPath *selectedPath)
    {
        self.title = cellWeak.textLabel.text;
        NSLog(@"Oooh, this row was selected.");
    };
    
    switch (indexPath.row)
    {
        case 0:
            {
                cell.textLabel.text = @"First row";
                cell.detailTextLabel.text = @"This is the row number 1, or row index 0.";
            }
            break;
        
        case 1:
            {
                cell.textLabel.text = @"Row two";
                cell.detailTextLabel.text = @"Could be the second row? Sure?";
            }
            break;
        
        case 2:
            {
                cell.textLabel.text = @"First row";
                cell.detailTextLabel.text = @"This is the row number 1, or row index 0.";
                cell.didSelectBlock = ^(NSIndexPath *selectedPath)
                {
                    self.title = @"Third row selected";
                    NSLog(@"A specific log for the third row, yes?");
                };
            }
            break;
            
        default:
            break;
    }
    
    return cell;
}

If the syntax highlighting isn't working above, I'm a terrible Drupal admin. Sigh.

In the example above, the behavior of the first and second rows are shared in the block defined outside the switch while the 3rd row overrides the didSelectBlock in it's own case.

Added Benefits

With the use of blocks, we get its benefits, too. The most relevant would be the scoping. What we have already defined in the tableView:cellForRowAtIndexPath: can easily be used inside the defined blocks. If we were using tableView:didSelectRowAtIndexPath:, we'd have to redo the definition of the variables again. Or I'm just not a very good programmer?

Future

Maybe making this into a class extension instead of its own class would make things simpler with less changes. Any takers? None? Fine, I'll do it later.

Category: