美文网首页iOS-面试iOS基本功
iOS 事件机制 -- 从触发到响应

iOS 事件机制 -- 从触发到响应

作者: 那时J花开 | 来源:发表于2019-08-05 11:57 被阅读0次

    当手指触摸到屏幕时, 一个触摸事件就在系统中产生了.通过进程间通信(IPC), 最终传递给合适的应用,并找到应用中的最佳响应者进行响应. 整个流程大概如下:

    事件响应链.png
    1. 系统响应阶段
    • 当手指触摸到屏幕, 屏幕感受到触摸后, 系统会将触摸交给IOKit.framework处理. IOKit.framework在内部会将触摸封装成一个IOHIDEvent对象. 并且通过mach port递交给SpringBoard.app(系统桌面)进程

    mach port 进程端口,各进程之间通过它进行通信。
    SpringBoad.app 是一个系统进程,可以理解为桌面系统,可以统一管理和分发系统接收到的触摸事件。

    • SpringBoard进程收到这个IOHIDEvent对象, 会触发SpringBoard .app进程中的主线程runloopsource1事件回调. 此时SpringBoard .app会根据桌面状态, 判断是否有运行在前台的进程. 若无app在前台运行, 那么会触发SpringBoard .app进程主线程runloopsource0回调, 事件由SpringBoard进程内部消耗. 若有app在前台运行, 则SpringBoard通过mach portIOHIDEvent分发给该app. 接下来就是该app内部消耗这个IOHIDEvent对象的过程.

    • app接受到这个IOHIDEvent对象, 其主线程的runloop被唤醒, 其中的source1回调被触发, 并触发source1中的source0回调, 在这个source0回调中, IOHIDEvent对象被封装成为一个UIEvent对象. 此时app正式开始对事件的响应.

    • source0回调将这个UIEvent对象添加到给UIApplication对象的事件队列中. 事件出队后, UIApplication开始一系列寻找最佳响应者的过程, 称为Hit-Testing.

    2. Hit-Testing
    • 从逻辑上来讲, 探测链机制是最先发生的. 当产生触摸事件后, iOS系统会通过Hit-Testing来找到最佳响应者, 去响应这个触摸事件. 只要用到了UIView的两个方法:
    // recursively calls -pointInside:withEvent:. point is in the receiver's coordinate system
    - (nullable UIView *)hitTest:(CGPoint)point withEvent:(nullable UIEvent *)event;
    
    // default returns YES if point is in bounds
    - (BOOL)pointInside:(CGPoint)point withEvent:(nullable UIEvent *)event;
    

    前者会通过recursively calls递归调用来返回一个适合响应触摸事件的UIView对象:

    hitTest

    如果通过demo来验证Hit-Testing, 会发现, 其实整个Hit-Testing过程会发生两次. 对此苹果官方有相应的回复:

    Yes, it’s normal. The system may tweak the point being hit tested between the calls. Since hitTest should be a pure function with no side-effects, this should be fine.

    • UIApplication通过Hit-Testing找到了最佳响应者并且遍历得到其所有的UIGestureRecognizer, 然后根据最佳响应者UIGestureRecognizerUIWindow创建UITouches对象, 并将其保存在UIEvent中.

    • UIApplicationUIEvent发送给UIWindow, UIWindow首先将事件发送给UIGestureRecognizer, 然后发送给最佳响应者, 事件沿Responder Chain传递.

    • UIGestureRecognizer开始识别自己的gesture, 当某个gestureRecognizer识别成功后, UIGestureRecognizer将独占所有需要的UITouches, 识别成功的gesture所关联的UITouch中的hitTest view收到-touchesCancelled()消息, 并且此后该hitTest view不再收到该UITouch事件

    • target: action:触发, action方法内部实现相应的触摸事件响应.事件处理完成, 若runloop无其他事件处理, 则runloop进入休眠, 等待下一个事件到来.

    • 识别成功的gestureRecognizer所关联的UITouches的其他所有gestureRecognizer收到-touchesCancelled()消息, 此后不再收到该UITouch事件.

    • 如果没有识别成功的gestureRecognizer, 那么hitTest view将不会收到-touchesCancelled()消息. 若有最佳响应者能够处理该事件. 那么事件处理完成, 若runloop无其他事件处理, 则runloop进入休眠, 等待下一个事件到来.

    • 最佳响应者没能够处理该事件, 则进行下个步骤:Responder Chain

    3. Responder Chain

    通过Hit-Testing找到的视图拥有最先对触摸事件进行响应的机会. 如果这个视图无法处理触摸事件, 就会沿着Responder Chain向上进行传递.直到找到可以处理事件的视图, 或者一直到UIApplication都没有能够处理, 该事件就会被废弃掉. 若runloop无其他事件, 则进入休眠, 等待下一个事件到来.

    相关文章

      网友评论

        本文标题:iOS 事件机制 -- 从触发到响应

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