面试复习-事件响应链总结

2021-04-20  本文已影响0人  云无心

首先参考响应者链条 https://www.jianshu.com/p/c294d1bd963d

系统响应

  1. 首先 屏幕接收到点击后,IOKit会进行事件捕捉
  2. 而后通过 mach port传递给SpringBoad进程
  3. SpringBoard进程因接收到触摸事件,触发了主线程runloop的source1事件源的回调
  4. 如果此时在桌面,则交给桌面系统去消耗该事件
  5. 如果此时在app前台,则通过IPC(进程通信)传给app进程

APP响应

  1. 通过 mach port收到SpringBoad的触摸事件,主线程runloop被唤醒,触发source1回调
  2. source1回调触发soirce0回调,将触摸事件封成UIEvent事件
  3. source0将事件添加到UIApplication对象的队列中,开始寻找最佳响应者hit-testing
  4. 寻找到最佳响应者后,开始事件的响应在响应链中的传递和响应
  5. 触摸事件要么被某个响应对象捕获后释放,要么无法找到响应对象后释放

hit-Testing

  1. UIApplication 通过 调用UIWindow的 hitTest:withEvent: 传递给UIWindow,依次从后往前遍历子视图传递
  2. 过程
    1. 判断是否可交互
      • 不允许交互:userInteractionEnabled = NO
      • 隐藏:hidden = YES 如果父视图隐藏,那么子视图也会隐藏,隐藏的视图无法接收事件
      • 透明度:alpha < 0.01 如果设置一个视图的透明度<0.01,会直接影响子视图的透明度。alpha:0.0~0.01为透明。
    2. 判断是否在视图中 if ([self pointInside:point withEvent:event] == NO) return nil;
    3. 判断是否在子视图中 CGPoint childP = [self convertPoint:point toView:childView];
      UIView *fitView = [childView hitTest:childP withEvent:event];
    4. 重写父视图 - (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event 可以实现超出点击

事件响应

  1. 事件的最佳响应者是 hit-tested view,他可以独吞事件 也可以往后传递
  2. 不操作默认往下分发,通过nextResponder
  3. 在 touchesMoved: withEvent: 是否调用父类同名方法决定是否往下分发

事件优先级 UIResponder、UIGestureRecognizer、UIControl

UIResponder 和 UIGestureRecognizer

  1. 如果成功识别了 UIGestureRecognizer 则 优先进行 手势,而中止 hit-tested view的 UIResponder 过程。
  2. 触摸状态变化 的 begin 先发送到 手势 再 hit-tested
  3. 顺序为 手势begin —— hit-test begin—— 手势识别成功——手势end ——hit-test cancel
  4. 属性:cancelsTouchesInView 。默认YES,代表手势成功后,屏蔽响应链的响应
  5. 属性:delaysTouchesBegan 。默认NO,代表在手势识别期间不会调用 hit-test begin,move等
  6. 属性:delaysTouchesEnded 。默认YES,代表手势失败后,会延迟0.15s调用响应者的 touchesEnded:withEvent:,若NO,立即调用

UIControl

- (BOOL)beginTrackingWithTouch:(UITouch *)touch withEvent:(nullable UIEvent *)event;
- (BOOL)continueTrackingWithTouch:(UITouch *)touch withEvent:(nullable UIEvent *)event;
- (void)endTrackingWithTouch:(nullable UITouch *)touch withEvent:(nullable UIEvent *)event;
- (void)cancelTrackingWithEvent:(nullable UIEvent *)event;

这几个方法是在 touch 系列里面调用的

  1. UIControl会阻止父视图上的手势识别器行为,也就是UIControl处理事件的优先级比UIGestureRecognizer高,但前提是相比于父视图上的手势识别器。
  2. UIControl比其父视图上的手势识别器具有更高的事件响应优先级。
  3. 准确地说只适用于系统提供的有默认action操作的UIControl,例如UIbutton、UISwitch等的单击

UIResponser
一:响应者链 UIResponser包括了各种Touch message 的处理,比如开始,移动,停止等等。常见的 UIResponser 有 UIView及子类,UIViController,APPDelegate,UIApplication等等。
回到响应链,响应链是由UIResponser组成的,那么是按照哪种规则形成的。

A: 程序启动 UIApplication会生成一个单例,并会关联一个APPDelegate。APPDelegate作为整个响应链的根建立起来,而``UIApplication会将自己与这个单例链接,即UIApplication的nextResponser(下一个事件处理者)为APPDelegate`。

B:创建UIWindow 程序启动后,任何的UIWindow被创建时,UIWindow内部都会把nextResponser设置为UIApplication单例。UIWindow初始化rootViewController,rootViewController的nextResponser会设置为UIWindow

C:UIViewController初始化 loadView, VC的view的nextResponser会被设置为VC.

D:addSubView addSubView操作过程中,如果子subView不是VC的View,那么subView的nextResponser会被设置为superView。如果是VC的View,那就是 subView -> subView.VC ->superView如果在中途,subView.VC被释放,就会变成subView.nextResponser = superView

上一篇下一篇

猜你喜欢

热点阅读