Online Book Reader

Home Category

iOS Recipes - Matt Drance [36]

By Root 257 0
project?

Solution

Finding the row that hosts a custom view or control is not particularly hard. The problem is, it’s easy to do wrong.

Let’s say each of our table cells has a button that uses our table view controller as a target. When the user taps any one of these buttons, the same single action is called. What if our table has 100 rows? We need to distinguish one row from another to know which button or row the user tapped.

- (IBAction)cellButtonTapped:(id)sender {

// Which table row is this button in?

}

Figure 20, What’s the index path for a given button? illustrates the problem at hand. There’s no easy or obvious way for your code to tell one cell button from another.

Figure 20. What’s the index path for a given button?

* * *

The tempting course of action would be to just walk right up the tree to the hosting table cell and ask the table view which row that cell corresponds to. After all, we know our own cell’s hierarchy.

- (IBAction)cellButtonTapped:(id)sender {

// Go get the enclosing cell manually

UITableViewCell *parentCell = [[sender superview] superview];

NSIndexPath *pathForButton = [self.tableView

indexPathForCell:parentCell];

}

This approach is probably the quickest, but it’s far from ideal, for a few reasons. First, it’s fragile. The previous code assumes the cell hierarchy won’t change. But if we move this button up or down one level, this code immediately breaks—and we may not remember why, or even notice, until the worst possible moment. Walking up the tree iteratively until we find a UITableViewCell is not a whole lot better. We want something short, sweet, and minimally error-prone.

Second, the previous solutions aren’t portable. The work we do here is likely to be done again for our next fancy interactive table. It would be great to have a solution we could drop into any project.

Let’s start by talking about a cleaner way to find the view’s enclosing row. UIView has some handy methods that allow us to translate points on the screen from one view’s coordinates to another’s. We can use this ‑convertPoint:toView: method to figure out where in our table view the tapped button resides; we’ll bypass the cell entirely. Once we have that adjusted point, we’ll pass it to ‑[UITableView indexPathForRowAtPoint:] and get our row index.

CellSubviewLocation/Classes/RootViewController.m

- (IBAction)cellButtonTapped:(id)sender {

UIButton *button = sender;

CGPoint correctedPoint =

[button convertPoint:button.bounds.origin toView:self.tableView];

NSIndexPath *indexPath =

[self.tableView indexPathForRowAtPoint:correctedPoint];

NSLog(@"Button tapped in row %d", indexPath.row);

}

This doesn’t involve any more code than the earlier “lazy” approaches, and it’s safer and more portable. We can make it even more portable if we want. Those two lines of code are hardly difficult to move around, but the convertPoint: methods are subtle enough that revisiting them months later can lead to some head-scratching. It’d be nice to solve this problem once and get back to business.

To do that, we’ll place this logic in a UITableView category. We’ll have to make some adjustments because the work is now being done by the table view instead of the table view controller, but the idea is the same.

CellSubviewLocation/Classes/UITableView+PRPSubviewAdditions.m

@implementation UITableView (PRPSubviewAdditions)

- (NSIndexPath *)prp_indexPathForRowContainingView:(UIView *)view {

CGPoint correctedPoint = [view convertPoint:view.bounds.origin

toView:self];

return [self indexPathForRowAtPoint:correctedPoint];

}

@end

Now that we’ve abstracted the busywork of converting the point to an index path, our table view controller just passes the relevant view and gets back the source index path.

- (IBAction)cellButtonTapped:(id)sender {

NSIndexPath *pathForButton =

[self.tableView prp_indexPathForRowContainingView:sender];

}

This recipe gives us a clean solution to tracing the origin of embedded table cell controls, no matter how the table or the cell is laid out.

Recipe 18 Organize

Return Main Page Previous Page Next Page

®Online Book Reader