Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

UITableViewCell skipped in responder chain

I'm attempting to trigger an event in a subview of a UITableViewCell, and let it bubble up the responder chain and be handled by a custom UITableViewCell subclass.

Basically:

SomeView.m (which is a subview of the UITableViewCell)

[self.button addTarget:nil action:@selector(someAction:) events:UIControlEventTouchUpInside]

SomeCustomCell.m

- (void)someAction:(id)sender {
     NSLog(@"cool, the event bubbled up to the cell");
}

And to test why this wasn't working, I've added the someAction: method on the ViewController and the ViewController is the one that ends up handling the event that bubbles up from the table view cell subview, even though the Cell should handle it. I've checked that the Cell is on the responder chain and I've verified that any views on the responder chain both above and below the cell will respond to the event if they implement the someAction: method.

What the heck is going on here?

Here's a project that shows it https://github.com/keithnorm/ResponderChainTest Is this expected behavior somehow? I haven't found any documentation stating UITableViewCell's are treated any differently than other UIResponder's.

like image 340
Keith Norman Avatar asked Jan 24 '14 07:01

Keith Norman


People also ask

What is responder chain swift?

The responder chain is the series of events that happen once we start interacting with the application on the iPhone. As an example, whenever we tap on an UITextfield, the whole series of responder initiates. It happens because of elements like UIView, UIViewController, UIApplication subclass UIResponder.

What is first responder UIKit?

Determining an Event's First Responder UIKit designates an object as the first responder to an event based on the type of that event. Event types include: Event type. First responder. Touch events.

What is UIResponder in IOS?

An abstract interface for responding to and handling events.


2 Answers

The cell seems to ask its table view for permission. To change that you can of course override

- (BOOL)canPerformAction:(SEL)action withSender:(id)sender
{
    return [self respondsToSelector:action];
}

Swift 3, 4, 5:

override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
    return self.responds(to: action)
}
like image 153
nschmidt Avatar answered Oct 29 '22 20:10

nschmidt


I've concluded that this is either a bug or undocumented intended behavior. At any rate, I ended up brute force fixing it by responding to the event in a subview and then manually propagating the message up the responder chain. Something like:

- (void)customEventFired:(id)sender {
  UIResponder *nextResponder = self.nextResponder;
  while (nextResponder) {
    if ([nextResponder respondsToSelector:@selector(customEventFired:)]) {
      [nextResponder performSelector:@selector(customEventFired:) withObject:sender];
      break;
    }
    nextResponder = nextResponder.nextResponder;
  }
}

I've also updated my demo project to show how I'm using this "fix" https://github.com/keithnorm/ResponderChainTest.

I still welcome any other ideas if anyone else figures this out, but this is the best I've got for now.

like image 22
Keith Norman Avatar answered Oct 29 '22 20:10

Keith Norman