What is best practice to handle a button touch event for a button of a custom UITableViewCell
?
my classes:
MyViewController
, MyCustomCell
I can think of three options:
First option- Have the button as a property of MyCustomCell
, and then add a target to it in the MyViewController
.m file with MyViewController
as the target.
MyViewController
.m file
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = @"customCell";
MyCustomCell *cell = (MyCustomCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[MyCustomCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
[cell.theButton addTarget:self
action:@selector(theButtonTapped:)
forControlEvents:UIControlEventTouchUpInside];
}
// Configure the cell...
[self configureCell:cell atIndexPath:indexPath];
return cell;
}
- (void)theButtonTapped:(UIButton *)sender
{
MyCustomCell *selectedCell = (MyCustomCell *)sender.superview;
if (selectedCell) {
NSIndexPath *indexPath = [self.tableView indexPathForCell:selectedCell];
MyModel *selectedModel = [self.model objectAtIndex:indexPath.row];
// do something with the model...
}
}
Second option- If the custom cell was made in IB, Set the nib File's Owner to be MyViewController
, implement buttonTapped:
method in MyViewController
and connect the button's Touch Up Inside event to the buttonTapped:
method.
Third option- if the custom cell wasn't made in IB, add a target to the button in the MyCustomCell
.m file with MyCustomCell
as the target.
Define a MyCustomCellDelegate
add @property (nonatomic, assign) id<MyCustomCellDelegate> delegate
to MyCustomCell
and call this delegate when button tapped.
Set MyViewController
as the cell's delegate when creating cells and implement the MyCustomCellDelegate
protocol.
MyCustomCell
.h file
@class MyCustomCell;
@protocol MyCustomCellDelegate <NSObject>
- (void)buttonTappedOnCell:(MyCustomCell *)cell;
@end
@interface MyCustomCell : UITableViewCell
@property (nonatomic, retain) UIButton *theButton;
@property (nonatomic, assign) id<MyCustomCellDelegate> delegate;
@end
MyCustomCell
.m file
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
// Initialization code
self.theButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
self.theButton.frame = CGRectMake(10,10,50,30);
[self addSubview:self.theButton];
[self.theButton addTarget:self
action:@selector(theButtonTapped:)
forControlEvents:UIControlEventTouchUpInside];
}
return self;
}
- (void)theButtonTapped:(UIButton *)sender
{
[self.delegate buttonTappedOnCell:self];
}
MyViewController
.m file
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = @"customCell";
MyCustomCell *cell = (MyCustomCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[MyCustomCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
cell.delegate = self;
}
// Configure the cell...
[self configureCell:cell atIndexPath:indexPath];
return cell;
}
- (void)buttonTappedOnCell:(MyCustomCell *)selectedCell
{
if (selectedCell) {
NSIndexPath *indexPath = [self.tableView indexPathForCell:selectedCell];
MyModel *selectedModel = [self.model objectAtIndex:indexPath.row];
// do something with the model...
}
}
Store the row of the cell as tag
property of your custom button.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
// bla bla bla
if (!cell)
{
//bla bla bla
[cell.yourButton addTarget:self selector:@selector(yourButtonTapped:) forControlEvents:UIControlEventTouchUpInside];
}
// bla bla bla
cell.yourButton.tag = indexPath.row;
}
-(void)yourButtonTapped:(id)sender
{
int tag = [(UIButton *)sender tag];
NSLog(@"tapped button in cell at row %i", tag);
}
Using tag, from my point of view, would break the strictness of your code. In addition, when you have multiple sections, using tag definitely would make a mess of your code.
To avoid this problem, you can subclass UITableViewCell
and make it hold an indexPath
property to let the cell know its precise position.
Another problem here is, if UITableView
invokes API to insert
or delete
row, you have to update visible cells' position data
I don't think that is the best practice.
There exists a better way.
I strongly recommend to use MVVM when you have to handle different touch events in your Cell.
In this pattern, your custom UITableViewCell
would hold a custom CellViewModel
. This class would be responsible for holding all data you associate with the cell, so you can retrieve the data and put the event handling logic inside the cell.
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