responder nextResponder

一.responder對象

在iOS系統中,能夠響應並處理事件的對象稱之爲responder object, UIResponder是所有responder對象的基類,在UIResponder類中定義了處理各種事件,包括觸摸事件(Touch Event)、運動事件(Motion Event)和遠程控制事件(Remote-Control Events)的編程接口,其中處理觸摸事件(Touch Event)的編程接口如下:
– touchesBegan:withEvent:
– touchesMoved:withEvent:
– touchesEnded:withEvent:
– touchesCancelled:withEvent:
這四個方法分別處理觸摸開始事件,觸摸移動事件,觸摸終止事件,以及觸摸跟蹤取消事件。

UIApplicationUIViewController,UIView和所有繼承自UIView的UIKit類(包括UIWindow,繼承自UIView)都直接或間接的繼承自UIResponder,所以它們的實例都是responder object對象,都實現了上述4個方法。UIResponder中的默認實現是什麼都不做,但UIKit中UIResponder的直接子類(UIView,UIViewController…)的默認實現是將事件沿着responder chain繼續向上傳遞到下一個responder,即nextResponder。所以在定製UIView子類的上述事件處理方法時,如果需要將事件傳遞給next responder,可以直接調用super的對應事件處理方法,super的對應方法將事件傳遞給next responder,即使用

[super touchesBegan:touches withEvent:event];

不建議直接向nextResponder發送消息,這樣可能會漏掉父類對這一事件的其他處理。

[self.nextResponder  touchesBegan:touches withEvent:event];

另外,在定製UIView子類的事件處理方法時,如果其中一個方法沒有調用super的對應方法,則其他方法也需要重寫,不使用super的方法,否則事件處理流程會很混亂。

注:UIKit框架的類層次結構圖見:UIKit Framework Reference

二.responder chain

上文提到了responder chain,responder chain是一系列連接的responder對象,通過responder對象可以將處理事件的責任傳遞給下一個,更高級的對象,即當前responder對象的nextResponder
iOS中responder chain的結構爲:

  • UIView的nextResponder屬性,如果有管理此view的UIViewController對象,則爲此UIViewController對象;否則nextResponder即爲其superview
  • UIViewController的nextResponder屬性爲其管理view的superview.
  • UIWindow的nextResponder屬性爲UIApplication對象。
  • UIApplication的nextResponder屬性爲nil。

iOS系統在處理事件時,通過UIApplication對象和每個UIWindow對象的sendEvent:方法將事件分發給具體處理此事件的responder對象(對於觸摸事件爲hit-test view,其他事件爲first responder),當具體處理此事件的responder不處理此事件時,可以通過responder chain交給上一級處理。

  1. 如果hit-test view或first responder不處理此事件,則將事件傳遞給其nextResponder處理,若有UIViewController對象則傳遞給UIViewController,傳遞給其superView。
  2. 如果view的viewController也不處理事件,則viewController將事件傳遞給其管理view的superView。
  3. 視圖層級結構的頂級爲UIWindow對象,如果window仍不處理此事件,傳遞給UIApplication.
  4. 若UIApplication對象不處理此事件,則事件被丟棄。

三.巧妙利用nextResponder

通過UIViewController的view屬性可以訪問到其管理的view對象,及此view的所有subviews。但是根據一個view對象,沒有直接的方法可以得到管理它的viewController,但我們使用responder chain可以間接的得到,代碼如下:

@implementation UIView (ParentController)
-(UIViewController*)parentController{
    UIResponder *responder = [self nextResponder];
    while (responder) {
	if ([responder isKindOfClass:[UIViewController class]]) {
		return (UIViewController*)responder;
	}
	responder = [responder nextResponder];
    }
    return nil;
}
@end
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章