美文网首页
面试复习-事件响应链总结

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

作者: 云无心 | 来源:发表于2021-04-20 13:31 被阅读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

    相关文章

      网友评论

          本文标题:面试复习-事件响应链总结

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