'寫在前面的話'
這些是我對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.