UITableViewCell跳过响应者链

我试图触发一个UITableViewCell子视图中的事件,并让它冒泡响应链,并由自定义的UITableViewCell子类处理。

基本上:

SomeView.m (这是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"); } 

为了testing为什么这不起作用,我在ViewController中添加了someAction:方法,而ViewController是最终处理从表视图单元格子视图中冒出的事件的一个,即使Cell应该处理它。 我已经检查过Cell是否在响应链上,并且我已经validation过,在响应者链上和响应者链上的任何视图都会响应事件,如果他们实现someAction:方法的话。

这到底是怎么回事?

这是一个项目,显示它https://github.com/keithnorm/ResponderChainTest这种预期的行为不知何故? 我还没有find任何文档说明UITableViewCell的处理任何不同于其他UIResponder的。

该单元格似乎要求其表视图的权限。 要改变,你当然可以覆盖

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

Swift 3:

 override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool { return responds(to: action) } 

我已经得出结论,这是一个错误或无证的预期行为。 无论如何,我最终通过在子视图中响应事件来强制修复它,然后手动将消息传播到响应者链中。 就像是:

 - (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; } } 

我也更新了我的演示项目,以显示我如何使用此“修复” https://github.com/keithnorm/ResponderChainTest

如果其他人想出来,我仍然欢迎任何其他的想法,但这是我现在最好的。

您可以将View.m中的代码更改为

  [button addTarget:nil action:@selector(customEventFired:) forControlEvents:(1 << 24)]; 

  [button addTarget:cell action:@selector(customEventFired:) forControlEvents:(1 << 24)]; 

这样做

  @implementation ContentView // uncomment this to see event caught by the cell's subview - (id)initWithFrame:(CGRect)frame { self = [super initWithFrame:frame]; if(self) { UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom]; [button setTitle:@"Click" forState:UIControlStateNormal]; [button setBackgroundColor:[UIColor blueColor]]; [button addTarget:self action:@selector(customEventFired:) forControlEvents:UIControlEventTouchUpInside]; button.frame = CGRectMake(4, 5, 100, 44); [self addSubview:button]; } return self; } - (void)customEventFired:(id)sender { UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"Event Triggered in cell subview" message:@"so far so good..." delegate:nil cancelButtonTitle:@"cancel" otherButtonTitles:nil, nil]; [alertView show]; } @end 

现在customEventFired:方法被调用

我认为这是最简单的解决scheme。 如果您没有指定目标,则事件将自动向响应者链上鼓吹。

 [[UIApplication sharedApplication]sendAction:@selector(customAction:) to:nil from:self forEvent:UIEventTypeTouches];