網上很多關于這方面的文章,但是決定還是如何使用響應者和響應者鏈出發(fā),然后來解釋一波兒,首先推薦去看官方文章Using Responders and the Responder Chain to Handle Events
本篇是對文章的翻譯
概述
應用程序使用響應對象接收和處理事件。UIResponder。類的任何實例對象都是響應者,公共子類包括UIView,UIViewController,UIApplication,響應者接收原始事件數據,并且必須處理事件或將其轉發(fā)給另一個響應者對象。 當您的應用收到事件時,UIKit會自動將該事件定向到最合適的響應者對象,稱為第一響應者。未處理的事件從響應者傳遞到活動響應者鏈中的響應者,這是應用程序的響應者對象的動態(tài)配置。 圖1顯示了應用程序中的響應者,其界面包含label,文本 text field,button兩個background views。 該圖還顯示了事件如何在響應者鏈之后從一個響應者移動到下一個響應者。

如果text field不處理事件,UIKit會將事件發(fā)送到文本字段的父UIView對象,然后是window的根視圖。 從根視圖開始,響應器鏈在將事件定向到窗口之前轉移到擁有的視圖控制器。 如果window無法處理事件,UIKit會將事件傳遞給UIApplication對象,如果該對象是UIResponder的實例而不是響應者鏈的一部分,則可能傳遞給app delegate。
確定事件的第一響應者
UIKit根據事件的類型將對象指定為事件的第一響應者。 事件類型包括:

- 觸摸事件(Touch events):第一響應者是觸摸點所在的視圖。
- 按壓事件(Press events):第一響應者是有焦點的響應者。
- 搖晃運動事件(Shake-motion events):第一響應者是由我們自己(或者UIKit)指定為第一響應者的對象。
- 遠程控制事件(Remote-control events):第一響應者是由我們自己(或者UIKit)指定為第一響應者的對象。
- 編輯菜單消息(Editing menu messages):第一響應者是由我們自己(或者UIKit)指定為第一響應者的對象。
注意:與加速計、陀螺儀和磁力計相關的運動事件不遵循響應者鏈,
Core Motion會將這些事件直接傳遞給我們指定的對象。有關更多信息,可以參看Core Motion Framework。
控件使用動作消息直接與其關聯的目標對象進行通信。 當用戶與控件交互時,控件會向其target對象發(fā)送操作消息。 動作消息不是事件,但它們仍然可以利用響應者鏈。 當控件的target對象為nil時,UIKit從target對象開始并遍歷響應者鏈,直到找到實現相應操作方法的對象。 例如,UIKit編輯菜單使用此行為來搜索響應器對象,這些對象實現具有cut:,copy:或paste:等名稱的方法。
手勢識別器在其視圖之前接收touch和press事件。 如果視圖的手勢識別器無法識別觸摸序列,則UIKit會將touch發(fā)送到視圖。 如果視圖沒有處理touch,UIKit會將它們傳遞給響應者鏈。 有關使用手勢識別器處理事件的更多信息,請參閱處理UIKit手勢。
確定哪個響應者包含touch事件
UIKit使用基于視圖的hit-testing來確定$touch事件發(fā)生的位置。 具體來說,UIKit將touch位置與視圖層次結構中視圖對象的邊界進行比較。
UIView的 hitTest:withEvent: 方法遍歷視圖層次結構,查找包含指定觸摸(touch)的最深子視圖,該子視圖成為觸摸事件的第一個響應者。
觸摸發(fā)生時,UIKit會創(chuàng)建一個UITouch對象并將其與視圖關聯。 當觸摸位置或其他參數發(fā)生變化時,UIKit會使用新信息更新相同的UITouch對象。 唯一不改變的屬性是視圖。 (即使觸摸位置移動到原始視圖之外,觸摸視圖屬性中的值也不會改變。)觸摸結束時,UIKit會釋放UITouch對象。
hitTest:withEvent: 方法介紹
- 如果觸摸位置位于視圖邊界之外,則
hitTest:withEvent:方法將忽略該視圖及其所有子視圖。 因此,當視圖的clipsToBounds屬性為NO時,即使它們恰好包含觸摸,也不會返回該視圖邊界之外的子視圖。
2.hitTest:withEvent:方法會遍歷當前視圖層,并調用每個子視圖的pointInside:withEvent:方法來判斷子視圖的邊界是否包含觸摸點。如果pointInside:withEvent:返回YES,則會同樣遍歷子視圖的視圖層,直到找到包含指定點的最上層的視圖。如果視圖不包含該觸摸點,就忽略此視圖層次結構的分支。因此我們可以覆overridehitTest:withEvent以隱藏子視圖中的觸摸事件。 - 此方法忽略掉被隱藏,禁用用戶交互或alpha級別小于0.01的視圖對象。在確定命中時,此方法不會考慮視圖的內容。因此,即使指定的點位于該視圖內容的透明部分,仍然可以返回視圖。
位于接收者界限之外的點永遠不會被報告為命中,即使它們實際上位于接收者的子視圖中。如果當前視圖的clipsToBounds屬性設置為NO并且受影響的子視圖超出視圖的邊界,hitTest:withEvent:方法也不會返回命中了此視圖。
改變響應者鏈
您可以通過覆蓋響應程序對象的nextResponder屬性來更改響應程序鏈。 執(zhí)行此操作時,下一個響應者是您返回的對象。
許多UIKit類已經覆蓋此屬性并返回特定對象,包括:
-
對象。 如果視圖是視圖控制器的根視圖,則下一個響應者是視圖控制器; 否則,下一個響應者是視圖的父視圖。
-
UIViewController對象。
如果視圖控制器的視圖是window的根視圖,則下一個響應者是window object。
如果視圖控制器由另一個視圖控制器呈現,則下一個響應者是呈現視圖控制器。 -
UIWindow對象。 窗口的下一個響應者是UIApplication對象。 -
UIApplication對象。 下一個響應者是UIApplication,但僅當應用程序委托是UIResponder的實例且不是視圖,視圖控制器或應用程序對象本身時。