nextResponder與Responder Chain

nextResponder與Responder Chain

 

一、關於nextResponder相關研究

首先我們來看一下nextResponder的官方解釋:

-(UIResponder*)nextResponder

The UIResponder class does not store or set the next responderautomatically, instead returning nil by default. Subclasses must override this method to set the nextresponder. UIView implements this method byreturning the UIViewController object that manages it (if it has one) or itssuperview (if it doesn’t); UIViewController implements the method by returningits view’s superview; UIWindow returnsthe application object, and UIApplication returns nil.

根據上面的解釋:UIResponder是不會自動存儲和設置這個nextResponder指針,默認都是返回nil。UIResponder的子類,必須重寫這個方法去設置下一個響應者。(在這裏需要理解:蘋果其實已經幫我們把UIView、UIViewController、UIWindow和UIApplication都默認實現了nextResponder方法,可以看我後面的測試結論)

1)UIView實現這個方法,它返回的下一個響應者要分兩種情況:如果這個視圖有一個UIViewController對象管理它,它就會返回這個UIViewController對象;如果這個視圖沒有一個UIViewController對象管理它,它就會返回它的父視圖的指針;

2)UIViewController實現這個方法,它返回它的視圖管理器的指針;

3)UIWindow則返回UIApplication的指針;

4)UIApplication則返回的是nil。


我們可以在UIViewController裏做一下測試代碼:

-(void)viewDidAppear:(BOOL)animated{

    NSLog(@"%@",self.nextResponder);

    NSLog(@"%@",[self.viewsuperview]);

    NSLog(@"%@",self.view);

    NSLog(@"%@",self.view.nextResponder);

    NSLog(@"1:%@",[self.viewsuperview].nextResponder);

    NSLog(@"2:%@",[self.viewsuperview].nextResponder.nextResponder);

    NSLog(@"3:%@",[self.viewsuperview].nextResponder.nextResponder.nextResponder);

    NSLog(@"%@",self.navigationController.nextResponder);

    NSLog(@"1%@",self.navigationController.view);

    NSLog(@"%@",self.navigationController.view.nextResponder);

    NSLog(@"%@",[self.navigationController.view superview]);

    NSLog(@"%@",[self.navigationController.viewsuperview].nextResponder);

    NSLog(@"%@",[self.navigationController.viewsuperview].nextResponder.nextResponder);

    NSLog(@"%@",[self.navigationController.viewsuperview].nextResponder.nextResponder.nextResponder);

}

經過上述測試代碼,可以得出如下結論:

1、UIViewController.nextResponder是UIViewController.view.superview;

2UIViewController.view.superview.nextResponder:如果UIViewController是UINavigationController管理的,那麼就是UIViewController向UINavigationController過渡的一個視圖,這個視圖的nextResponder就是UINavigationController.view;

3、UIViewController.view.nextResponder是UIViewController

4、如果UIViewController是App的根視圖的控制器,那麼UIViewController.nextResponder是UIWindow,也就是UIViewController的superview;

5、同理,所有的是UIViewController的子類,都是具有上述的性質

6、UIWindow.nextResponder是UIApplication

7、UIApplication.nextResponder是UIApplicationDelegate;

8、UIApplicationDelegate.nextResponder是nil;

9、如果A視圖是加載在B視圖上,即A是B的子視圖(是通過addSubview加載)。


二、關於Responder Chain的研究

這個Responder Chain是依賴於nextResponder的實現鏈接的,進而形成一條“響應鏈”。(就類似於MFC裏的事件響應鏈)我們先看看官方關於ResponderChain的相關的解釋:

The Responder Chain Follows a Specific Delivery Path

Ifthe initial object—either the hit-test view or the first responder—doesn’thandle an event, UIKit passes the event to the next responder in the chain.Each responder decides whether it wants to handle the event or pass it along toits own next responder by calling the nextRespondermethod.This process continues until aresponder object either handles the event or there are no more responders.

Theresponder chain sequence begins when iOS detects an event and passes it to aninitial object, which is typically a view. The initial view has the firstopportunity to handle an event. Figure 2-2 shows two different event deliverypaths for two app configurations. An app’s event delivery path depends on itsspecific construction, but all event delivery paths adhere to the sameheuristics.

Figure 2-2 The responder chain on iOS

 

For the app on the left, the event follows this path:

1.The initial view attempts to handle the event or message. If itcan’t handle the event, it passes the event to its superview, because theinitial view is not the top most view in its view controller’s view hierarchy.

2.The superview attempts to handle the event. If the superviewcan’t handle the event, it passes the event to its superview, because it isstill not the top most view in the view hierarchy.

3.The topmost view in the view controller’s view hierarchy attemptsto handle the event. If the topmost view can’t handle the event, it passes theevent to its view controller.

4.The view controller attempts to handle the event, and if itcan’t, passes the event to the window.

5. If the window object can’t handle the event, it passes the eventto the singleton app object.

6. If the app object can’t handle the event, it discards the event.


The app on the right follows a slightly different path, but all eventdelivery paths follow these heuristics:

1. A view passes an event up its view controller’s view hierarchy until itreaches the topmost view.

2. The topmost view passes the event to its view controller.

3.The view controller passes the event to its topmost view’ssuperview.Steps 1-3 repeat until the event reaches the root view controller.

4.The root view controller passes the event to the window object.

The windowpasses the event to the app object.

Important: If you implement a customview to handle remote control events, action messages, shake-motion events withUIKit, or editing-menu messages, don’t forward the event or message to  nextResponder directly to send it up the responder chain.Instead, invoke the superclass implementation of the current event handlingmethod and let UIKit handle the traversal of the responder chain for you.

從上述的解釋中,我們可以得出,它是沿着響應鏈向上尋找事件的處理者。


三、運用響應鏈

1、UIViewController的view屬性可以訪問到其管理的view以及view的所有subviews。但是根據一個view對象,沒有直接的方法可以取管理它的viewController,這裏就可以使用responder chain接的得到,代如下:

@implementationUIView (ParentUIViewController)

-(UIViewController*)parentViewController{

    UIResponder *responder = [selfnextResponder];

    while (responder) {

            if ([responderisKindOfClass:[UIViewController class]]) {

                        return(UIViewController*)responder;

            }

            responder = [respondernextResponder];

    }

    return nil;

}

@end


2、重載UIResponder的下面4個接口,可以實現一些自定義的手勢動作效果:

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event;

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event;

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event;

- (void)touchesCancelled:(NSSet*)touches withEvent:(UIEvent*

個人通過測試,很多時候並不能按照上面“Important”裏說的:不能直接發送給nextResponder,是需要我們理解響應鏈,可以主動跳過更爲低層視圖的nextResponder。因爲很多很少跨域了多層,這個事件往往響應不夠及時和流暢,甚至是達不到我們需要的體驗效果。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章