iOS响应者链详解

iOS程序的响应链是一个非常有意思的事情,明确了响应链的调用顺序,那么就可以在响应链中操作响应的对象,这样有助于实现一些特殊的需求,比如控件重写,自定义控件的响应顺序。

这里先明确几个概念

UIEvent-> 是事件本身,事件中包含三种状态的事件,Touch屏幕触摸事件、Motion感应事件(例如摇晃)、Remote远程事件(其他比如手表、手环之类)

UIResponder->响应者,专门来响应用户的事件及对事件的处理

Hit-Testing -> 寻找最佳响应者

Responder chain -> 响应链本身

UIControl -> 类似于手势,比手势更加的精简,继承自uiview,基类来自于UIResponder

了解这几个概念之后,顺着代码来看看响应者链的顺序。

在这里写了一个HView继承自UIView,重写了三个方法,重要的是 overridefunchitTest(_point:CGPoint,withevent:UIEvent?) ->UIView?和 overridefuncpoint(insidepoint:CGPoint,withevent:UIEvent?) ->Bool这两个方法

需要记得的是这两个方法是组合起来使用的

打好断点,看一下调用的顺序

* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1

 hit-Testing`HView.hitTest(point=(x = 75.666666666666657, y = 76.333333333333314), event=0x0000600002f700c0, self=0x00007fc974106380) at HView.swift:14:15

[UIView(Geometry) _hitTest:withEvent:windowServerHitTestWindow:] + 87

-[UIDropShadowView hitTest:withEvent:] + 327

-[UIView(Geometry) _hitTest:withEvent:windowServerHitTestWindow:] + 87

-[UITransitionView hitTest:withEvent:] + 44

-[UIView(Geometry) hitTest:withEvent:]_block_invoke + 121

[UIWindow _hitTestToPoint:forEvent:windowServerHitTestWindow:]_block_invoke + 84

-[UIWindowScene _topVisibleWindowPassingTest:] + 482

 [UIWindow _hitTestToPoint:forEvent:windowServerHitTestWindow:] + 238

 hit-Testing`static UIApplicationDelegate.main() at :0

 AppDelegate.$main(self=hit_Testing.AppDelegate) at AppDelegate.swift:10:1

 hit-Testing`main at :0


这里只保留了每一个阶段的调用,这样的顺序一目了然

HView -> UIView->UIDropShadowView->UIView->UITransitionView->UIView-> UIWindow->UIWindowScene->UIWindow->AppDelegate->main

再度精简HView -> UIView->UIDropShadowView->UITransitionView-> UIWindow->UIWindowScene->UIWindow->AppDelegate->main

通过打印获得了一个完整的调用链,其实最终的入口还是在main的代理AppDelegate中,当点击一个区域的时候,从AppDelegate中逐级的响应,直到找到最终的最佳响应者。

了解了响应者链的顺序,这里还有几个规则需要注意,响应者链从这个字面意思就可以知道这是一个链式的存在,UIView和UIViewController都是继承自UIResponder,UIResponder是链式存储,那么它自身必然是有一个指针指向下一个对象的。

1.UIView如果是ViewController的rootView,则UIView的nextResponder指向该ViewController,否则UIView的nextResponder指向的是UIView的superView

2.ViewController如果是UIWindow的rootViewControoler,则ViewController的nextResponder指向该UIWindow,否则,ViewController的nextResponder指向自身的前一个ViewController

3 UIWindow的nextResponder是指向AppDelegate的。



对于手势需要注意的点:

手势的优先级高于UIResponder,设置了手势之后,手势的四个阶段分别是touchesBegan,Moved,Ended,Cancelled,对于手势的响应最好是在Ended中去操作,因为Ended之后,才会去真正的处理事件,处理完事件之后系统再回调Cancelled方法。在Ended处理,减少从touchesBegan到Ended的传递,这样也是细微的优化。

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 当我们点击一个 button 时,button 的响应消息机制分为两块: 首先在视图层次中找到能响应消息的那个视图...
    Vergil_wj阅读 2,356评论 0 7
  • 一.基本概念 UIEvent 一个UIEvent对象描述一次用户交互行为。例如:用户点击手机屏幕、摇晃手机以后,系...
    一片姜汁阅读 571评论 0 1
  • 当我们在使用微信等工具,点击扫一扫,就能打开二维码扫描视图。在我们点击屏幕的时候,iphone OS获取到了用户进...
    lbfly_boy阅读 673评论 0 0
  • 系统响应阶段 1.手指触碰屏幕,屏幕感受到触摸后,将事件交由IOKit来处理。 2.IOKIT将触摸事件封装成IO...
    荒漠现甘泉阅读 1,063评论 1 4
  • 本文主要讲解iOS触摸事件的一系列机制,涉及的问题大致包括: 触摸事件由触屏生成后如何传递到当前应用? 应用接收触...
    Leoeoo阅读 1,770评论 0 7