按键(HOME键、锁屏键、音量键等)、传感器(摇晃、加速等)、触摸屏幕等【物理事件】会触发IOKit.framework生成一个IOHIDEvent对象,然后SpringBoard会接收这个对象并通过mach port发给当前App的进程;接下来进程会触发RunLoop的基于port的Source1回调一个__IOHIDEventSystemClientQueueCallback()的API,这个API会相应触发Source0来调用__UIApplicationHandleEventQueue(),而此API再将传递到此的IOHIDEvent处理包装成上层所熟悉的UIEvent。最后UIEvent会被分发给UIWindow根据Respond chain来响应事件。
梳理整个流程如下:
物理事件 (按键、传感器、触摸等)
|
IOHIDEvent (由IOKit.framework生成,SpringBoard接收)
|
App进程 (由mach port内核消息通信机制传递Event,SpringBoard->App)
|
触发Source1
|
回调 __IOHIDEventSystemClientQueueCallback()
|
触发Source0
|
回调__UIApplicationHandleEventQueue()
|
将IOHIDEvent封装成UIEvent
|
识别此事件是UIGesture或屏幕旋转等
|
分发UIWindow
|
根据响应链交给对应的responder进行事件回调
而这整个事件处理流程是基于RunLoop的基本处理循环进行的。在main函数开始后,主线程的runloop对象被创建完。如UIEvent、UI绘制等会统一在主线程的runloop对象的即将进入休眠前的时间点触发各自对应的代理回调方法,然后runloop进入休眠,直到被timer定时器或Source1发来的内核消息事件唤醒,再分别对Timer、Source0、Source1发来的事件进行处理回调。