I have a UITableView
with 5 UITableViewCells
. Each cell contains a UIButton
which is set up as follows:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *identifier = @"identifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier];
if (cell == nil) {
cell = [[UITableView alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identifier];
[cell autorelelase];
UIButton *button = [[UIButton alloc] initWithFrame:CGRectMake(10, 5, 40, 20)];
[button addTarget:self action:@selector(buttonPressedAction:) forControlEvents:UIControlEventTouchUpInside];
[button setTag:1];
[cell.contentView addSubview:button];
[button release];
}
UIButton *button = (UIButton *)[cell viewWithTag:1];
[button setTitle:@"Edit" forState:UIControlStateNormal];
return cell;
}
My question is this: in the buttonPressedAction:
method, how do I know which button has been pressed. I've considered using tags but I'm not sure this is the best route. I'd like to be able to somehow tag the indexPath
onto the control.
- (void)buttonPressedAction:(id)sender
{
UIButton *button = (UIButton *)sender;
// how do I know which button sent this message?
// processing button press for this row requires an indexPath.
}
What's the standard way of doing this?
Edit:
I've kinda solved it by doing the following. I would still like to have an opinion whether this is the standard way of doing it or is there a better way?
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *identifier = @"identifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier];
if (cell == nil) {
cell = [[UITableView alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identifier];
[cell autorelelase];
UIButton *button = [[UIButton alloc] initWithFrame:CGRectMake(10, 5, 40, 20)];
[button addTarget:self action:@selector(buttonPressedAction:) forControlEvents:UIControlEventTouchUpInside];
[cell.contentView addSubview:button];
[button release];
}
UIButton *button = (UIButton *)[cell.contentView.subviews objectAtIndex:0];
[button setTag:indexPath.row];
[button setTitle:@"Edit" forState:UIControlStateNormal];
return cell;
}
- (void)buttonPressedAction:(id)sender
{
UIButton *button = (UIButton *)sender;
int row = button.tag;
}
What's important to note is that I can't set the tag in the creation of the cell since the cell might be dequeued instead. It feels very dirty. There must be a better way.
Here's how I do it. Simple and concise:
I would use the tag property like you said, setting the tag like so:
then getting the tag inside of the buttonPressedAction like so:
Or
Pretty straightforward actually:
Working well for me :P
if you want to adjust your target-action setup, you can include the event parameter in the method, and then use the touches of that event to resolve the coordinates of the touch. The coordinates still need to be resolved in the touch view bounds, but that may seem easier for some people.
Found a nice solution to this problem elsewhere, no messing around with tags on the button:
To do (@Vladimir)'s answer is Swift:
Although checking for
indexPath != nil
gives me the finger..."NSIndexPath is not a subtype of NSString"