響應鏈

每一個應用有一個響應者鏈,我們的視圖結(jié)構(gòu)是一個N叉樹(一個視圖可以有多個子視圖,一個子視圖同一時刻只有一個父視圖),而每一個繼承UIResponder的對象都可以在這個N叉樹中扮演一個節(jié)點。當葉節(jié)點成為最高響應者的時候荠呐,從這個葉節(jié)點開始往其父節(jié)點開始追朔出一條鏈,那么對于這一個葉節(jié)點來講,這一條鏈就是當前的響應者鏈昔园。響應者鏈將系統(tǒng)捕獲到的UIEvent與UITouch從葉節(jié)點開始層層向下分發(fā)蔓榄,期間可以選擇停止分發(fā),也可以選擇繼續(xù)向下分發(fā)默刚。

例子:
我用SingleView模板創(chuàng)建了一個新的工程甥郑,它的主Window上只有一個UIViewController,其View之上有一個Button荤西。這個項目中所有UIResponder的子類所構(gòu)成的N叉樹為這樣的結(jié)構(gòu):



那么他看起來并不像N叉樹澜搅,但是不代表者不是一顆N叉樹,當我們項目復雜之后邪锌,這個View可不可以有多個UIButton節(jié)點勉躺?所以他就是一棵樹。
實際上我們要把這棵樹寫完整觅丰,應該還要算上UIButton的UILabel和UIImageView饵溅,因為他們也是UIReponder的子類。這里先不考慮了妇萄。
我們對UIButton來講蜕企,他此時若是葉節(jié)點,那么這時我們針對他所在的響應鏈來說冠句,他在他之前的響應者就應該是我們controller的view(樹中的葉節(jié)點比父節(jié)點永遠更優(yōu)先被分發(fā)事件,但是并不是說他就能在時間上先響應轻掩,我們下面講為什么)。所以我們嘗試在任意地方打印這個Button的nextReponder對象懦底。nextResponder對象是UIReponder類的實例方法唇牧,它會返回任意對象在樹中的上一個響應者實例:

控制臺輸出消息:**2013-09-21 03:40:25.989**  **響應鏈**  **[614:60b] <UIView: 0x16555e10; frame = (0 0; 320 568); autoresize = RM+BM; layer = <CALayer: 0x16555e70>>** ```
我們可以根據(jù)這個UIView的尺寸來得知,他就是我們唯一的控制器中的那個UIView聚唐。 
接下來我們再打印下這個UIView的下一個響應者是誰: 
```NSLog(@"%@",_testButton.nextResponder.nextResponder);
輸出:  **2013-09-21 03:45:03.914**  **響應鏈**  **[621:60b] <RSViewController: 0x15da0e30>**  ```
依次看奋构,接著加一個nextResponder: 
```**2013-09-21 03:50:49.428**  **響應鏈**  **[669:60b] (null)** ```
為什么這里ViewController沒有父親呢?注意這句代碼我是寫在ViewDidLoad中拱层,而我們知道這個方法的生命周期比較早弥臼,所以我們換個地方寫或者延遲一段時間再打印,兩種方法都可以得到結(jié)果(由此可以推理出我們響應者樹的構(gòu)造過程是在ViewDidLoad周期中來完成的根灯,這個函數(shù)會將當前實例的構(gòu)成的響應者子樹合并到我們整個根樹中): 
```**2013-09-21 03:53:47.304**  **響應鏈**  **[681:60b] <UIWindow: 0x14e24200; frame = (0 0; 320 568); gestureRecognizers = <NSArray: 0x14e242e0>; layer = <UIWindowLayer: 0x14e244a0>>** ```
再繼續(xù)往上追朔:double delayInSeconds = 2.0; dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC)); dispatch_after(popTime, dispatch_get_main_queue(), ^(void){ NSLog(@"%@",_testButton.nextResponder.nextResponder.nextResponder.nextResponder); });
```**2013-09-21 03:56:22.043**  **響應鏈**  **[690:60b] <UIApplication: 0x15659c00>** ```
再加一個```:**2013-09-21 03:56:51.186**  **響應鏈**  **[696:60b] <RSAppDelegate: 0x16663520>** ```
那么我們的appDelegate還有沒有父節(jié)點?```**2013-09-21 03:57:22.588**  **響應鏈**  **[706:60b] (null)** ```
沒有了径缅,注意,一個從葉節(jié)點開始分發(fā)的事件烙肺,最多也就只能分發(fā)到我們的AppDelegate了纳猪!  
這個樹形結(jié)構(gòu)在我們的項目中尤為重要,舉個栗子桃笙,如果我們想在一個view中重寫UITouchEvent的4個方法氏堤,并且不影響他的父視圖也響應這些事件,就要注意你重寫的方式了搏明,比如我們在ViewController中重寫touchBegan如下: 
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{ NSLog(@"ViewController接收到觸摸事件");}
在appDelegate的中同樣也寫上這一段:-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{ NSLog(@"appDelegate接收到觸摸事件");}
那么究竟是誰被觸發(fā)呢鼠锈? 
```**2013-09-21 04:02:49.405**  **響應鏈**  **[743:60b] ```ViewController**  **接收到觸摸事件**  
這個很好理解闪檬,我剛剛也說了,viewController明顯是appDelegate的子節(jié)點购笆,他有事件分發(fā)的優(yōu)先權(quán)粗悯。如果我們想兩個地方都觸發(fā)呢?這里super一下就可以了:-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{ [super touchesBegan:touches withEvent:event]; NSLog(@"ViewController接收到觸摸事件");}
```輸出:**2013-09-21 04:07:26.206**  **響應鏈**  **[749:60b] appDelegate**  **接收到觸摸事件**  ```
**2013-09-21 04:07:26.208**  **響應鏈**  **[749:60b] ViewController**  **接收到觸摸事件**  ```
注意看時間戳同欠,appDelegate雖然優(yōu)先級別不如ViewController样傍,但是他響應的時間上面足足比ViewController早了0.002秒,我這里試了幾次铺遂,都是相差0.002秒衫哥。那么我們分析一下這里的響應者鏈是怎樣工作的: 
用戶手指觸摸到了UIView上,由于我們沒有重寫UIView的UITouchEvent,所以他里面和super執(zhí)行的一樣的,將該事件繼續(xù)分發(fā)到UIViewController襟锐; 
UIViewController的TouchBegan被我們重寫了撤逢,如果我們不super,那么我們在這里寫響應代碼捌斧。事件到這里就不繼續(xù)分發(fā)了∪矗可想而知捞蚂,UIViewController祖先節(jié)點:UIWindow,UIApplication跷究,AppDelegate都無權(quán)被分發(fā)此事件姓迅。 
如果我們super了TouchBegan,那么此次觸摸事件由 
ViewController分發(fā)給UIWindow, 
UIWindow繼而分發(fā)給UIApplication俊马, 
UIApplication再分發(fā)給AppDelegate丁存, 
于是我們在ViewController和appDelegate的touchBegan方法中都捕獲到了這次事件。 
到這里大家應該對這個響應者樹有一個很好的理解了吧? 
接下來我們再談談第一響應者柴我,和UIButton上的事件分發(fā)解寝。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市艘儒,隨后出現(xiàn)的幾起案子聋伦,更是在濱河造成了極大的恐慌,老刑警劉巖界睁,帶你破解...
    沈念sama閱讀 217,542評論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件觉增,死亡現(xiàn)場離奇詭異,居然都是意外死亡翻斟,警方通過查閱死者的電腦和手機逾礁,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,822評論 3 394
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來访惜,“玉大人嘹履,你說我怎么就攤上這事腻扇。” “怎么了植捎?”我有些...
    開封第一講書人閱讀 163,912評論 0 354
  • 文/不壞的土叔 我叫張陵衙解,是天一觀的道長。 經(jīng)常有香客問我焰枢,道長蚓峦,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,449評論 1 293
  • 正文 為了忘掉前任济锄,我火速辦了婚禮暑椰,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘荐绝。我一直安慰自己一汽,他們只是感情好,可當我...
    茶點故事閱讀 67,500評論 6 392
  • 文/花漫 我一把揭開白布低滩。 她就那樣靜靜地躺著召夹,像睡著了一般。 火紅的嫁衣襯著肌膚如雪恕沫。 梳的紋絲不亂的頭發(fā)上监憎,一...
    開封第一講書人閱讀 51,370評論 1 302
  • 那天,我揣著相機與錄音婶溯,去河邊找鬼鲸阔。 笑死,一個胖子當著我的面吹牛迄委,可吹牛的內(nèi)容都是我干的褐筛。 我是一名探鬼主播,決...
    沈念sama閱讀 40,193評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼叙身,長吁一口氣:“原來是場噩夢啊……” “哼渔扎!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起信轿,我...
    開封第一講書人閱讀 39,074評論 0 276
  • 序言:老撾萬榮一對情侶失蹤赞警,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后虏两,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體愧旦,經(jīng)...
    沈念sama閱讀 45,505評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,722評論 3 335
  • 正文 我和宋清朗相戀三年定罢,在試婚紗的時候發(fā)現(xiàn)自己被綠了笤虫。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,841評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖琼蚯,靈堂內(nèi)的尸體忽然破棺而出酬凳,到底是詐尸還是另有隱情,我是刑警寧澤遭庶,帶...
    沈念sama閱讀 35,569評論 5 345
  • 正文 年R本政府宣布宁仔,位于F島的核電站,受9級特大地震影響峦睡,放射性物質(zhì)發(fā)生泄漏翎苫。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,168評論 3 328
  • 文/蒙蒙 一榨了、第九天 我趴在偏房一處隱蔽的房頂上張望煎谍。 院中可真熱鬧,春花似錦龙屉、人聲如沸呐粘。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,783評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽作岖。三九已至,卻和暖如春五芝,著一層夾襖步出監(jiān)牢的瞬間痘儡,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,918評論 1 269
  • 我被黑心中介騙來泰國打工与柑, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留谤辜,地道東北人蓄坏。 一個月前我還...
    沈念sama閱讀 47,962評論 2 370
  • 正文 我出身青樓价捧,卻偏偏與公主長得像,于是被迫代替她去往敵國和親涡戳。 傳聞我的和親對象是個殘疾皇子结蟋,可洞房花燭夜當晚...
    茶點故事閱讀 44,781評論 2 354

推薦閱讀更多精彩內(nèi)容