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?
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.
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.
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.)
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];
}
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];
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With