什么是響應者鏈?ios面試攻克篇(三)


    '寫在前面的話'
這些是我對iOS面試時會碰到的問題的解決方法,整理出來分享給大家,有些錯誤不要
太好笑,希望對大家有所幫助。大家有更好的解決辦法也歡迎溝通交流。
一直以來都有寫點兒東西的想法,就從筆記、從閱讀開始吧,加油!'



iOs中的響應者鏈(Responder Chain)是用于確定事件響應者的一種機制,其中的事件主要指觸摸事件(Touch Event),該機制和UIKit中的UIResponder類緊密相關。響應觸摸事件的都是屏幕上的界面元素,而且必須是繼承自UlResponder 類的界面類(包括各種常見的視圖類及其視圖控制器類,如UIView和UIViewController)才可以響應觸摸事件。


一個事件響應者的完成主要經過兩個過程: hitTest方法命中視圖和響應者鏈確定響應者。hitTest方法首先從頂部UIApplication往下調用(從父類到子類),直到找到命中者,然后從命中者視圖沿著響應者鏈往上傳遞尋找真正的響應者。

如圖下所示界面結構,最頂部是一一個UIWindow窗口,其下對應一個唯一-的根 視圖,根視圖上可以不斷疊加嵌套各種子視圖,構成一棵樹。需要注意的是,父節點里面嵌套著子節點,即子節點的frame包含在父節點的frame內,但是子節點不一定是父節點的子類, 它們是組合關系而非繼承關系。


視圖節點圖 和 視圖樹屏幕效果圖


一:響應者鏈

UIResponser包括了各種Touch message的處理,比如開始,移動,停止等等。常見的 UIResponser UIView及子類,UIViController,APPDelegate,UIApplication等等。
回到響應鏈,響應鏈是由UIResponser組成的,那么是按照哪種規則形成的?

+ A: 程序啟動
UIApplication會生成一個單例,并會關聯一個'APPDelegate'。
APPDelegate作為整個響應鏈的根建立起來,而``UIApplication會將自己與這個單例鏈接,
即UIApplication的nextResponser(下一個事件處理者)為APPDelegate`。
+ B:創建UIWindow
程序啟動后,任何的UIWindow被創建時,UIWindow內部都會把nextResponser設置為UIApplication單例。
UIWindow初始化rootViewController,rootViewController的nextResponser會設置為UIWindow
+ C:UIViewController初始化
loadView, VC的view的nextResponser會被設置為VC.
+ D:addSubView
addSubView操作過程中,如果子subView不是VC的View,那么subView的nextResponser會被設置為superView。
如果是VC的View,那就是' subView' ->' subView.VC' ->'superView'如果在中途,
subView.VC被釋放,就會變成subView.nextResponser = superView



過程


我們使用一個現實場景來解釋這個問題:當一個用點擊屏幕上的一個按鈕,這個過程具體發生了什么。

1.用戶觸摸屏幕,系統硬件進程會獲取到這個點擊事件,將事件簡單處理封裝后存到系統中,由于硬件檢測進程和當前App進程是兩個進程,所以進程兩者之間傳遞事件用的是端口通信。硬件檢測進程會將事件放到APP檢測的那個端口。

2.APP啟動主線程RunLoop會注冊一個端口事件,來檢測觸摸事件的發生。當事件到達,系統會喚起當前APP主線程的RunLoop。來源就是App主線程事件,主線程會分析這個事件。

3.最后,系統判斷該次觸摸是否導致了一個新的事件, 也就是說是否是第一個手指開始觸碰,如果是,系統會先從響應網中 尋找響應鏈。如果不是,說明該事件是當前正在進行中的事件產生的一個Touch message, 也就是說已經有保存好的響應鏈



響應者鏈條

響應者鏈條: 其實就是很多響應者對象(繼承自 UIResponder 的對象)一起組合起來的鏈條稱之為響應者鏈條。

一般默認做法是控件將事件順著響應者鏈條向上傳遞,將事件交給上一個響應者進行處理。

那么如何判斷當前響應者的上一個響應者是誰呢?有以下兩個規則:

判斷當前是否是控制器的 View,如果是控制器的 View,上一個響應者就是控制器。
如果不是控制器的 View,上一個響應者就是父控件,當有 view 能夠處理觸摸事件后,開始響應事件。 系統會調用 view 的以下方法:

1. (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event;
2. (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event;
3. (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event;
4. (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event;

可以多對象共同響應事件。只需要在以上方法重載中調用 super 的方法。

大致的過程 initial view –> super view –> ……–> view controller –> window –> Application

需要特別注意的一點是,傳遞鏈中是沒有 controller 的,因為 controller 本身不具有大小的概念。但是響應鏈中是有 controller 的,因為 controller 繼承自 UIResponder。

UIApplication –> UIWindow –>遞歸找到最合適處理的控件 –> 控件調用 touches 方法 –> 判斷是否實現 touches 方法 –> 沒有實現默認會將事件傳遞給上一個響應者 –> 找到上一個響應者 –> 找不到方法作廢

PS:利用響應者鏈條我們可以通過調用 touches 的 super 方法,讓多個響應者同時響應該事件。


謝謝你長的這么好看,還關注我!!!點個贊唄!!
這就是響應鏈相關的點,如果有什么不對的請留言提示,然后有什么別的需要改進的提示請聯系我我會及時補充~

over.over.

部分文章來自轉載他人,如有侵權請聯系作者刪除

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容