IOS事件處理機制(關於觸發者和響應者的確認)

事件處理機制

在iOS中發生觸摸後,事件會加入到UIApplication事件隊列(在這個系列關於iOS開發的第一篇文章中咱們分析iOS程序原理的時候就說過程序運行後UIApplication會循環監聽用戶操做),UIApplication會從事件隊列取出最前面的事件並分發處理,一般先分發給應用程序主窗口,主窗口會調用hitTest:withEvent:方法(假設稱爲方法A,注意這是UIView的方法),查找合適的事件觸發視圖(這裏一般稱爲「hit-test view」):html

  1. 在頂級視圖(key window的視圖)上調用pointInside:withEvent:方法判斷觸摸點是否在當前視圖內;
  2. 若是返回NO,那麼A返回nil;
  3. 若是返回YES,那麼它會向當前視圖的全部子視圖(key window的子視圖)發送hitTest:withEvent:消息,遍歷全部子視圖的順序是從subviews數組的末尾向前遍歷(從界面最上方開始向下遍歷)。
  4. 若是有subview的hitTest:withEvent:返回非空對象則A返回此對象,處理結束(注意這個過程,子視圖也是根據pointInside:withEvent:的返回值來肯定是返回空仍是當前子視圖對象的。而且這個過程當中若是子視圖的hidden=YES、userInteractionEnabled=NO或者alpha小於0.1都會並忽略);
  5. 若是全部subview遍歷結束仍然沒有返回非空對象,則A返回頂級視圖;

上面的步驟就是點擊檢測的過程,其實就是查找事件觸發者的過程。觸摸對象並不是就是事件的響應者(例如上面第一個例子中沒有重寫KCImage觸摸事件時,KCImge做爲觸摸對象,可是事件響應者倒是UIViewController),檢測到了觸摸的對象以後,事件究竟是如何響應呢?這個過程就必須引入一個新的概念「響應者鏈」。數組

什麼是響應者鏈呢?咱們知道在iOS程序中不管是最後面的UIWindow仍是最前面的某個按鈕,它們的擺放是有先後關係的,一個控件能夠放到另外一個控件上面或下面,那麼用戶點擊某個控件時是觸發上面的控件仍是下面的控件呢,這種前後關係構成一個鏈條就叫「響應者鏈」。在iOS中響應者鏈的關係能夠用下圖表示:app

iOS_responder_chain_2x

當一個事件發生後首先看initial view可否處理這個事件,若是不能則會將事件傳遞給其上級視圖(inital view的superView);若是上級視圖仍然沒法處理則會繼續往上傳遞;一直傳遞到視圖控制器view controller,首先判斷視圖控制器的根視圖view是否能處理此事件;若是不能則接着判斷該視圖控制器可否處理此事件,若是仍是不能則繼續向上傳遞;(對於第二個圖視圖控制器自己還在另外一個視圖控制器中,則繼續交給父視圖控制器的根視圖,若是根視圖不能處理則交給父視圖控制器處理);一直到window,若是window仍是不能處理此事件則繼續交給application(UIApplication單例對象)處理,若是最後application仍是不能處理此事件則將其丟棄。ide

這個過程你們理解起來並不難,關鍵問題是在這個過程當中各個對象如何知道本身能不能處理該事件呢?對於繼承UIResponder的對象,其不能處理事件有幾個條件:ui

  • userInteractionEnabled=NO 
  • hidden=YES 
  • alpha=0~0.01 
  • 沒有實現開始觸摸方法(注意是touchesBegan:withEvent:而不是移動和結束觸摸事件)

固然前三點都是針對UIView控件或其子控件而言的,第四點能夠針對UIView也能夠針對視圖控制器等其餘UIResponder子類。對於第四種狀況這裏再次強調是對象中重寫了開始觸摸方法,則會處理這個事件,若是僅僅寫了移動、中止觸摸或取消觸摸事件(或者這三個事件都重寫了)沒有寫開始觸摸事件,則此事件該對象不會進行處理。htm

相信到了這裏你們對於上面點擊圖片爲何不能拖拽已經很明確了。事實上經過前面的解釋你們應該能夠猜到即便KCImage實現了開始拖拽方法,若是在KCTouchEventViewController中設置KCImage對象的userInteractionEnabled爲NO也是能夠拖拽的。對象

 

轉自:崔江濤 http://www.cnblogs.com/kenshincui/p/3950646.html#remoteControl  很是感謝博主的詳細介紹blog

相關文章
相關標籤/搜索