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的传递,这样也是细微的优化。

你可能感兴趣的:(iOS响应者链详解)