Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

UITableView Cell - get IndexPath.row from button?

I currently have a button defined in a cell and a method to track its UITouchDown action as shown:

- (void) clickedCallSign:(id)sender {

    int index = [sender tag];
    NSLog(@"event triggered %@",index);

}

- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {
    //Callsign button
    UIButton *button;

    CGRect rect = CGRectMake(TEXT_OFFSET_X, BORDER_WIDTH, LABEL_WIDTH, LABEL_HEIGHT);
    button = [[UIButton alloc] initWithFrame:rect];
    cell.tag=[indexPath row];
    button.tag=[indexPath row];
    [button addTarget:self action:@selector(clickedCallSign:) forControlEvents:UIControlEventTouchDown];
    [button setBackgroundColor:[UIColor redColor]];
    [button setTitle:@"hello" forState:UIControlStateNormal];
    [cell.contentView addSubview:button];
    [button release];   
}

However when I click a cell in the simulator, the console debug message is: "event triggered (null)" and my app crashes shortly after.

How can I correctly get the indexPath.row value into my clickedCallSign method?

like image 912
dpigera Avatar asked Aug 14 '10 04:08

dpigera


People also ask

How do you get the indexPath row when a button in a cell is tapped?

add an 'indexPath` property to the custom table cell. initialize it in cellForRowAtIndexPath. move the tap handler from the view controller to the cell implementation. use the delegation pattern to notify the view controller about the tap event, passing the index path.

How can we use a reusable cell in UITableView?

For performance reasons, a table view's data source should generally reuse UITableViewCell objects when it assigns cells to rows in its tableView(_:cellForRowAt:) method. A table view maintains a queue or list of UITableViewCell objects that the data source has marked for reuse.


3 Answers

First off, index is an int, so your NSLog needs to look like this (note the %d):

NSLog(@"event triggered %d", index);

(It's possible that this leads to a crash, but it's also likely that something else entirely is going that causes the instability.)

like image 94
Ben Zotto Avatar answered Oct 04 '22 02:10

Ben Zotto


Tag is good until you haven't both sections and rows. Try another way to get index path:

- (void)tableView:(UITableView*)tableView willDisplayCell:(UITableViewCell*)cell forRowAtIndexPath:(NSIndexPath*)indexPath {

    //...

    [button addTarget:self action:@selector(clickedCallSign:withEvent:) forControlEvents:UIControlEventTouchDown];

    //...

}

// Get the index path of the cell, where the button was pressed
- (NSIndexPath*)indexPathForEvent:(id)event
{
    NSSet *touches = [event allTouches];
    UITouch *touch = [touches anyObject];
    CGPoint currentTouchPosition = [touch locationInView:self.tableView];
    return [self.tableView indexPathForRowAtPoint:currentTouchPosition];
}

- (IBAction)clickedCallSign:(id)sender withEvent:(UIEvent*)event
{
    NSIndexPath* buttonIndexPath = [self indexPathForEvent:event];
}
like image 27
JastinBall Avatar answered Oct 04 '22 04:10

JastinBall


If you don't want to use the tag field, have the button invoke this method:

- (void)tapAccessoryButton:(UIButton *)sender
{
    UIView *parentView = sender.superview;

    // the loop should take care of any changes in the view heirarchy, whether from
    // changes we make or apple makes.
    while (![parentView.class isSubclassOfClass:UITableViewCell.class])
        parentView = parentView.superview;

    if ([parentView.class isSubclassOfClass:UITableViewCell.class]) {
        UITableViewCell *cell = (UITableViewCell *) parentView;
        NSIndexPath *indexPath = [self.tableView indexPathForCell:cell];
        [self tableView:self.tableView accessoryButtonTappedForRowWithIndexPath:indexPath];
    }
}
like image 26
mahboudz Avatar answered Oct 04 '22 02:10

mahboudz