由Nil-Targeted Actions说起iOS中的响应者链

在开发中,做用户交互最常用的就是target-action 模式了。但是如果target的传入参数为nil会怎样呢?

Apple 在UIContro.h里给出了说明:

// passing in nil as the target goes up the responder chain. The action may optionally include the sender and the event in that order
- (void)addTarget:(nullable id)target action:(SEL)action forControlEvents:(UIControlEvents)controlEvents;

什么是响应者
应用程序用来接收和响应事件的对象就是响应者。在UIKit中其代码表现为UIResponder或其子类的实例对象。


什么是响应者链?
响应者链,是一条抽象链条,该链条的每个节点都是一个响应者。是通过UIResponder一个属性串联起来的

 @property(nonatomic, readonly) UIResponder *nextResponder; 

注意: UIResponder 中该属性默认返回Nil。

不过,UIKit中UIResponder子类已经给出了一个默认实现

由Nil-Targeted Actions说起iOS中的响应者链_第1张图片
App中的默认响应者链
  • 响应链的意义:在第一响应者不处理该事件的时候,将其传递个下一个响应者,直到事件被处理或因响应链结束没有处理而被丢弃。
  • 传递是怎么进行的?
//触摸类事件
- (void)touchesBegan:(NSSet *)touches withEvent:(nullable UIEvent *)event;
- (void)touchesMoved:(NSSet *)touches withEvent:(nullable UIEvent *)event;
- (void)touchesEnded:(NSSet *)touches withEvent:(nullable UIEvent *)event;
- (void)touchesCancelled:(NSSet *)touches withEvent:(nullable UIEvent *)event;
- (void)touchesEstimatedPropertiesUpdated:(NSSet *)touches NS_AVAILABLE_IOS(9_1);

//3D touch类型
- (void)pressesBegan:(NSSet *)presses withEvent:(nullable UIPressesEvent *)event NS_AVAILABLE_IOS(9_0);
- (void)pressesChanged:(NSSet *)presses withEvent:(nullable UIPressesEvent *)event NS_AVAILABLE_IOS(9_0);
- (void)pressesEnded:(NSSet *)presses withEvent:(nullable UIPressesEvent *)event NS_AVAILABLE_IOS(9_0);
- (void)pressesCancelled:(NSSet *)presses withEvent:(nullable UIPressesEvent *)event NS_AVAILABLE_IOS(9_0);

//运动类型
- (void)motionBegan:(UIEventSubtype)motion withEvent:(nullable UIEvent *)event NS_AVAILABLE_IOS(3_0);
- (void)motionEnded:(UIEventSubtype)motion withEvent:(nullable UIEvent *)event NS_AVAILABLE_IOS(3_0);
- (void)motionCancelled:(UIEventSubtype)motion withEvent:(nullable UIEvent *)event NS_AVAILABLE_IOS(3_0);
...

什么是第一响应者
UIKit认为处理当前事件最合适的那个响应者就是第一响应者。所以会出现针对不同事件当前第一响应者不同的情况。比如:触摸事件的第一响应者就是触摸发生的那个视图;摇晃手势的第一响应者是用户或者是UIKit指定的那个响应者。

注意:运动型事件(比如:摇晃运动)不会使用响应者链传递机制,而是直接调用已经指定好的第一响应者。


响应链条的应用:优雅的关闭键盘

Mac Guru Sean Heber taught us how:
[[UIApplication sharedApplication] sendAction:@selector(resignFirstResponder) to:nil from:nil forEvent:nil];
— Sean Heber (@BigZaphod) August 1, 2012


说回问题:
target 为nil的情况下,UIKit会先去找已经指定的第一响应者;如果没有,则调用用户触摸的视图。如果事件没有处理则沿着响应者链往下传递。


参考链接:

  1. https://www.cocoanetics.com/2012/09/the-amazing-responder-chain/
  2. https://developer.apple.com/documentation/uikit/understanding_event_handling_responders_and_the_responder_chain?language=objc

你可能感兴趣的:(由Nil-Targeted Actions说起iOS中的响应者链)