1

The following implementation works correctly, however it does not feel like the most elegant solution. Are there any best practices or different implementations for determining if a UIButton is tapped on a custom UITableViewCell?

- (IBAction)customCellButtonTapped:(id)sender {
    UIButton *button = (UIButton *)sender;
    NSIndexPath *indexPath = [NSIndexPath indexPathForRow:button.tag inSection:0];
    NSManagedObjectContext *context = [self.fetchedResultsController managedObjectContext];
    NSManagedObject *object = [self.fetchedResultsController objectAtIndexPath:indexPath];
    // Set the value of the object and save the context
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    TTCustomCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell" forIndexPath:indexPath];
    [self configureCell:cell atIndexPath:indexPath];
    [cell.customCellButton addTarget:self action:@selector(customCellButtonTapped:) forControlEvents:UIControlEventTouchUpInside];
    [cell.customCellButton setTag:indexPath.row];
    return cell;
}
  • What part of this doesn't seem elegant to you? – rmaddy Jan 11 '14 at 19:24
  • Because cells can be recycled at any time, using a button's tag and a common callback selector seems a pretty direct path to getting what you need...a function that gets called with an easy way to get the tag referring to the information the button is relevant to. There may be other ways, but the essentials are going to be very similar. – FuzzyBunnySlippers Jan 11 '14 at 19:33
  • why you do not initialize TTCustomCell in case it is nil? secondly you could put this ` [cell.customCellButton addTarget:self action:@selector(customCellButtonTapped:) forControlEvents:UIControlEventTouchUpInside]; [cell.customCellButton setTag:indexPath.row];` into `configureCell` method as well – Julian Jan 11 '14 at 19:33
  • @viperking Good call on that... – FuzzyBunnySlippers Jan 11 '14 at 19:33
  • @viperking Thank you for catching that. I refactored to initialize TTCustomCell and add the target customCellButtonTapped in configureCell. –  Jan 11 '14 at 19:47
  • https://stackoverflow.com/questions/1802707/detecting-which-uibutton-was-pressed-in-a-uitableview – erkanyildiz Dec 26 '17 at 17:03

2 Answers2

2

I agree that it is inelegant. Since the cells are being reused, the button tags must be changed to keep in synch. Not to mention, the tags might be needed for their real purpose, which isn't to tell the code what row the view is in.

Here's a method I use all the time in tableviews that contain controls:

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

    while (view && ![view isKindOfClass:[UITableViewCell self]]) {
        view = view.superview;
    }
    UITableViewCell *cell = (UITableViewCell *)view;
    return [self.tableView indexPathForCell:cell];
}

Now, in

- (IBAction)customCellButtonTapped:(id)sender {

    NSIndexPath *indexPath = [self indexPathOfSubview:sender];
    // use this to access your MOC

   // or if we need the model item...
   id myModelItem = self.myModelArray[indexPath.row];

   // or if we need the cell
   UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:indexPath];
danh
  • 62,181
  • 10
  • 95
  • 136
1

If you've already got a subclass of the cell, you could always implement a protocol that the owner implements, e.g:

Custom Cell

@protocol TTCustomCellDelegate <NSObject>
    - (void)customCellWasTapped:(TTCustomCell *)cell withSomeParameter:(id)parameter;
@end

@interface TTCustomCell : UITableViewCell
@property (nonatomic, weak) id<TTCustomCellDelegate> delegate;
@end

@implementation
- (void)buttonWasTapped
{
    if(self.delegate) 
        [self.delegate customCellWasTapped:self withSomeParameter:whateverYouNeed];
}

ViewController

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    ...
    cell.delegate = self;
    ...
}

- (void)customCellWasTapped:(TTCustomCell *)cell withSomeParameter:(id)parameter
{
    id thing = cell.somePropertyUniqueToThisCell;
    id otherThing = parameter;
}
Goos
  • 121
  • 6