美文网首页
iOS 开发-事件传递响应链

iOS 开发-事件传递响应链

作者: Lizzzzzzhen | 来源:发表于2017-06-13 10:44 被阅读138次

    当我们点击屏幕时,iPhone OS 获取到了用户"单击"这一行为,操作系统把包含这些点击事件的信息封装成 UITouchUIEvent 形成的实例,然后找到当前运行的程序,逐级找到能够响应这个事件的对象,知道没有响应者响应。这一寻找的过程称为响应链

    事件响应链

    响应者

    在 iOS 中,能够响应事件的对象都是 UIResponder 的子类对象。
    UIResponder 提供了用户点击的四个回调方法,分别对应点击、移动、点击结束和取消点击,其中取消点击只有在程序强制退出或来电视才会调用。


    UIResponder 点击事件

    响应链传递

    系统时怎么通过用户点击的位置找到处理点击事件的 view ?
    上文说过系统通过不断查找下一个响应者来响应点击事件,而所有的课加护空间都是 UIResponder 直接或者间接的子类,那么我们是否可以在这个类的头文件中找到关键的属性呢?正好存在这么一个方法 - (nullable UIResponder*)nextResponder;,通过方法名不难获取当前 view 的下一个响应者,那么我们重写 touchesBegan方法, 逐级获取下一个响应者,直到没有响应者位置。
    相关代码如下:

    - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
    {
        UIResponder * next = [self nextResponder];
        NSMutableString * prefix = @"".mutableCopy;
     
        while (next != nil) {
            NSLog(@"%@%@", prefix, [next class]);
            [prefix appendString: @"--"];
            next = [next nextResponder];
        }    
    }
    
    

    运行结果:

    AView
    --UIView
    ----ViewController
    ------UIWindow
    --------UIApplication
    ----------AppDelegate
    

    虽然结果非常有层次,但是从系统逐级查找响应者的角度上来说,这个输出的顺序是刚好相反的。为什么会出现这种问题呢?我们可以看到输出中存在一个ViewController类,说明UIViewController也是UIResponder的子类。但是我们可以发现,controller是一个view的管理者,即便它是响应链的成员之一,但是按照逻辑来说,控制器不应该是系统查找对象之一,通过nextResponder方法查找的这个思路是不正确的。

    后来在 UIView 中发现这两个方法,分别返回 UIview 和 BooL 类型的方法:

    UIView 两个方法

    一个方法是返回响应点击事件的对象,
    另一个是根据点击坐标返回事件是否发生在本视图内。

    响应者栈:
    所有响应者都是在查找中返回可响应点击的视图,因此可以推测,UIApplication 对象维护这自己的一个响应者栈,当 pointInside:withEvent: 返回 YES 时候,响应者入栈。


    响应者栈

    栈顶作为最先响应的对象,如果 AVView 不处理事件,那么出栈,移交给 UIView,依次下去,知道事件得到了处理或者到达 APPDelegate 后依旧未响应,事件被摒弃为止。

    相关文章

      网友评论

          本文标题:iOS 开发-事件传递响应链

          本文链接:https://www.haomeiwen.com/subject/nqxdqxtx.html