? ? ? 當(dāng)你手指觸摸屏幕后會發(fā)生以下事情:觸摸事件被封裝成一個UIEvent事件,去當(dāng)前iOS操作系統(tǒng)的active app隊列中取當(dāng)前活躍的APP,把event傳給它--->event傳給UIApplication--->傳給UIWindow的rootViewController(rootVC)--->調(diào)用rootVC.view的所有subviews的hitTest:event:方法。哪個view的hitTest:event方法返回非nil值,則觸摸事件就交給該view處理。
? ? ? ?當(dāng)設(shè)計一個app的時候,想動態(tài)的去響應(yīng)一個事件。例如,在屏幕上的一個觸摸事件可能在不同的對象中都發(fā)生,并且你不得不決定由哪一個對象來響應(yīng)這個事件并且嘗試去理解怎么樣的一個對象接收了到這個事件。
? ? ? ?當(dāng)一個常見的用戶事件發(fā)生的時候,UIKit會創(chuàng)建一個事件對象Event Object,該對象包含了事件處理所必須得一些信息。然后它會將事件對象置于激活的app事件隊列。例如觸摸事件,該觸摸時事件對象是一系列觸摸信息包裝集。例如手勢事件,該事件是一個動態(tài)的變量它取決于你使用了什么框架以及你感興趣的手勢事件類型。
? ? ? ? 一個事件會游走于指定的傳遞路徑很長的時間直到它被處理。首先,這個單例 UIApplication 對象會從事件隊列頂部拿出一個事件對象用于分發(fā)處理。比較典型的就是,它會發(fā)送這個事件給 Window 對象,Wiindow對象會遞交事件給原始對象 initial object去處理。initial object取決于事件的類型。
? ? ? ?觸摸事件:對于觸摸事件,window對象會嘗試著首先將事件傳遞給觸摸事件發(fā)生點得View。這個View被視為“命中測試view” (hit-test view)。尋找“命中測試view”的過程被稱作“命中測試”,關(guān)于“命中測試”會在下面的命中測試返回觸摸事件發(fā)生點的view有詳情描述。
? ? ? ?手勢和遠程控制事件:對于這些事件,window對象發(fā)送震動手勢或者遠程控制事件給第一響應(yīng)者去處理,關(guān)于第一響應(yīng)者的定義在下面的響應(yīng)者鏈的構(gòu)造中有詳情描述。
?? ? ? 最終所有的事件響應(yīng)路徑都是為了去尋找那個能夠響應(yīng)并處理該事件的對象。因此,UIkit會首先發(fā)送該事件給最適合處理該事件的對象。對于觸摸事件,這個最適合處理的對象就是 hit-test view既“命中測試view”,并且對于其它事件,這個對象就是“第一響應(yīng)者”。下面的幾個部分將詳細的解釋更多的關(guān)于“命中測試view”和第一響應(yīng)者的選擇。
? ? ? ?命中測試返回觸摸事件發(fā)生點的view
? ? ? ?iOS使用“命中測試”(hit-testing)去尋找觸摸發(fā)生下的view。命中測試會執(zhí)行檢測判斷是否改觸摸點發(fā)生在某個具體的view的相對邊界之內(nèi)。如果檢測是的,它就會遞歸的去檢測該view的所有子view。該view的層級最底端view包含觸摸點,它就成為了“命中測試view”。之后iOS就會決定誰是命中測試view,并且遞交觸摸事件給它處理。
? ? ? ? 為了去闡明這個過程,假設(shè)用戶觸摸 view E如圖。iOS會以這樣的順序去尋找命中測試view通過檢測所有的子view.

? ? ? ? 方法hitTest:withEvent傳入CGPoint和UIEvent返回命中測試view。這個方法hitTest:withEvent開始執(zhí)行通過調(diào)用自身的ponitInside:withEvent方法。如果傳入hitTest:withEvent的point在view的邊界之內(nèi)。ponitInside:withEvent方法就會返回YES。然后該方法會遞歸調(diào)用hitTest:withEvent方法在每一個返回YES的子view上。
? ? ? ? 如果傳入的hitTest:withEvent的點不在view的邊界之內(nèi),首先會調(diào)用ponitInside:withEvent方法返回NO,該point會被忽略,并且hitTest:withEvent返回nil,如果一個子view返回NO,那么整個view層級的分支都會被忽略,因為如果觸摸點沒有發(fā)生在子view,她也不可能發(fā)生在任何子view的子view。這就意味著任何子view上面的點都在邊界之外并且它的父view也不能接受觸摸事件,因為觸摸點必須同時在父view和子view的邊界之內(nèi)。這種情況可能會發(fā)生,如果子view的clipsToBound屬性設(shè)為NO。
? ? ? ? 注意:一個觸摸事件對象將會被關(guān)聯(lián)于命中測試view的整個生命周期,即使這個觸摸后來移到了view的邊界之外。
? ? ? ? 命中測試view被賦予了第一個處理觸摸事件的機會,如果命中測試view不能處理該事件,該事件就會交付給view響應(yīng)者鏈的上一級處理直到系統(tǒng)找到一個能夠處理該事件的對象。