由Nil-Targeted Actions說起

weixin_34146805發表於2017-09-25

在開發中,做使用者互動最常用的就是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子類已經給出了一個預設實現

1482122-c5d96181564ba9c4.png
App中的預設響應者鏈
  • 響應鏈的意義:在第一響應者不處理該事件的時候,將其傳遞個下一個響應者,直到事件被處理或因響應鏈結束沒有處理而被丟棄。
  • 傳遞是怎麼進行的?
//觸控類事件
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(nullable UIEvent *)event;
- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(nullable UIEvent *)event;
- (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(nullable UIEvent *)event;
- (void)touchesCancelled:(NSSet<UITouch *> *)touches withEvent:(nullable UIEvent *)event;
- (void)touchesEstimatedPropertiesUpdated:(NSSet<UITouch *> *)touches NS_AVAILABLE_IOS(9_1);

//3D touch型別
- (void)pressesBegan:(NSSet<UIPress *> *)presses withEvent:(nullable UIPressesEvent *)event NS_AVAILABLE_IOS(9_0);
- (void)pressesChanged:(NSSet<UIPress *> *)presses withEvent:(nullable UIPressesEvent *)event NS_AVAILABLE_IOS(9_0);
- (void)pressesEnded:(NSSet<UIPress *> *)presses withEvent:(nullable UIPressesEvent *)event NS_AVAILABLE_IOS(9_0);
- (void)pressesCancelled:(NSSet<UIPress *> *)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

相關文章