關於響應者鏈,有以下一段介紹:每個應用有一個響應者鏈,咱們的視圖結構是一個N叉樹(一個視圖能夠有多個子視圖,一個子視圖同一時刻只有一個父視圖),而每個繼承UIResponder的對象均可以在這個N叉樹中扮演一個節點。當葉節點成爲最高響應者的時候,從這個葉節點開始往其父節點開始追朔出一條鏈,那麼對於這一個葉節點來說,這一條鏈就是當前的響應者鏈。響應者鏈將系統捕獲到的UIEvent與UITouch從葉節點開始層層向下分發,期間能夠選擇中止分發,也能夠選擇繼續向下分發。ios
那,我要是告訴大家,響應者鏈就是上面那段話介紹的,估計大家得拿板磚拍我了。這等於沒說。別急,先來舉個栗子:web
我用SingleView模板建立了一個新的工程,它的主Window上只有一個UIViewController,其View之上有一個Button。這個項目中全部UIResponder的子類所構成的N叉樹爲這樣的結構:app
那麼他看起來並不像N叉樹,可是不表明者不是一顆N叉樹,當咱們項目複雜以後,這個View可不能夠有多個UIButton節點?因此他就是一棵樹。函數
實際上咱們要把這棵樹寫完整,應該還要算上UIButton的UILabel和UIImageView,由於他們也是UIReponder的子類。這裏先不考慮了。spa
因此咱們嘗試在任意地方打印這個Button的nextReponder對象。nextResponder對象是UIReponder類的實例方法,它會返回任意對象在樹中的上一個響應者實例:對象
控制檯輸出信息以下:繼承
<UIView: 0x7f8973e92b60; frame = (0 0; 375 667); autoresize = W+H; layer = <CALayer: 0x7f8973e92ee0>>生命週期
我們能夠一直打印下去,獲取下一個Responder的下一個Responder,依次獲取的響應者是:事件
<ViewController: 0x7f8973c2ccf0>ci
(null)
爲何這裏ViewController沒有父親呢?
注意這句代碼我是寫在ViewDidLoad中,而咱們知道這個方法的生命週期比較早,因此咱們換個地方寫或者延遲一段時間再打印,兩種方法均可以獲得結果(由此能夠推理出咱們響應者樹的構造過程是在ViewDidLoad週期中來完成的,這個函數會將當前實例的構成的響應者子樹合併到咱們整個根樹中):
最後獲取就是上邊給出的那幅圖的樣子了。那說了這麼多,這個Responder到底有什麼用呢?
在AppDelegate裏面重寫touchesBegan方法:
在ViewController裏面也重寫:
用戶手指觸摸到了UIView上,因爲咱們沒有重寫UIView的UITouchEvent,因此他裏面和super執行的同樣的,將該事件繼續分發到UIViewController;
UIViewController的TouchBegan被咱們重寫了,若是咱們不super,那麼咱們在這裏寫響應代碼。事件到這裏就不繼續分發了。可想而知,UIViewController祖先節點:UIWindow,UIApplication,AppDelegate都無權被分發此事件。
若是咱們super了TouchBegan,那麼這次觸摸事件由
ViewController分發給UIWindow,
UIWindow繼而分發給UIApplication,
UIApplication再分發給AppDelegate,
因而咱們在ViewController和appDelegate的touchBegan方法中都捕獲到了此次事件。
可是這只是處理點擊事件順序,也便是確認了第一響應者以後的處理流程。
那尋找第一響應者的流程是怎樣的呢。
其實就是逆向走一遍,當沿着這條響應者鏈找到了第一響應者,那麼就會返回事件給本身的nextResponder去處理,直到appDelegate。
下面回到我們的主題,既然點擊按鈕,沒有觸發點擊事件,響應者鏈有很大嫌疑。
爲何這麼說呢??
我問你們,若是你點擊完按鈕以後,沒有找到第一響應者,或者是第一響應者找錯了,還會調用button的觸發事件嗎??顯而易見。
下面列舉常見的幾大緣由,有興趣的同窗能夠去試試。
這個理解起來就簡單一些,好比實現按鈕點擊事件所在的視圖控制器被回收了。可是因爲按鈕被添加到當前可見視圖上,按鈕沒有被回收,因此是可見的。可是點擊這個按鈕卻沒有任何做用。
單單是上面兩個方面並不能涵蓋全部的相似狀況,並且這節我們只是從UIButton入手。在具體的開發中,有不少經驗所不可以解釋的現象,可是上面兩點通常是優先考慮的。