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。因为很多很少跨域了多层,这个事件往往响应不够及时和流畅,甚至是达不到我们需要的体验效果。


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