首页 存档 技术 查看内容

iOS事件处理机制与图像渲染过程

2018-3-30 13:00 |来自: 互联网 362 0

摘要: 致歉声明: Peter在开发公众号功能时触发了一个bug,导致群发错误。对此我们深表歉意,并果断开除了Peter。以下交回给正文时间: iOS 事件处理机制与图像渲染过程 iOS RunLoop都干了什么 iOS 为什么必须在主线程 ...

致歉声明:

Peter在开发公众号功能时触发了一个bug,导致群发错误。对此我们深表歉意,并果断开除了Peter。以下交回给正文时间:


iOS 事件处理机制与图像渲染过程


iOS RunLoop都干了什么

RunLoop是一个接收处理异步消息事件的循环,一个循环中:等待事件发生,然后将这个事件送到能处理它的地方。

如图1-1所示,描述了一个触摸事件从操作系统层传送到应用内的main runloop中的简单过程。


图1-1

简单的说,RunLoop是事件驱动的一个大循环,如下代码所示

int main(int argc, char * argv[]) {
     //程序一直运行状态
     while (AppIsRunning) {
          //睡眠状态,等待唤醒事件
          id whoWakesMe = SleepForWakingU  p();
          //得到唤醒事件
          id event = GetEvent(whoWakesMe);
          //开始处理事件
          HandleEvent(event);
     }
     return 0;
}

RunLoop主要处理以下6类事件:

static void __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__();
static void __CFRUNLOOP_IS_CALLING_OUT_TO_A_BLOCK__();
static void __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__();
static void __CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION__();
static void __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__();
static void __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__();
  1. Observer事件,runloop中状态变化时进行通知。(微信卡顿监控就是利用这个事件通知来记录下最近一次main runloop活动时间,在另一个check线程中用定时器检测当前时间距离最后一次活动时间过久来判断在主线程中的处理逻辑耗时和卡主线程)。这里还需要特别注意,CAAnimation是由RunloopObserver触发回调来重绘,接下来会讲到。

  2. Block事件,非延迟的NSObject PerformSelector立即调用,dispatch_after立即调用,block回调。

  3. Main_Dispatch_Queue事件:**中dispatch到main queue的block会被dispatch到main loop执行。

  4. Timer事件:延迟的NSObject PerformSelector,延迟的dispatch_after,timer事件。

  5. Source0事件:处理如UIEvent,CFSocket这类事件。需要手动触发。触摸事件其实是Source1接收系统事件后在回调 __IOHIDEventSystemClientQueueCallback() 内触发的 Source0,Source0 再触发的 _UIApplicationHandleEventQueue()。source0一定是要唤醒runloop及时响应并执行的,如果runloop此时在休眠等待系统的 mach_msg事件,那么就会通过source1来唤醒runloop执行。

  6. Source1事件:处理系统内核的mach_msg事件。(推测CADisplayLink也是这里触发)。

RunLoop执行顺序的伪代码

SetupThisRunLoopRunTimeoutTimer(); // by ** timer
//通知即将进入runloop__CFRUNLLOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__(KCFRunLoopEntry);
do {
     __CFRunLoopDoObservers(kCFRunLoopBeforeTimers);
     __CFRunLoopDoObservers(kCFRunLoopBeforeSources);

     __CFRunLoopDoBlocks();  //一个循环中会调用两次,确保非延迟的NSObject PerformSelector调用和非延迟的dispatch_after调用在当前runloop执行。还有回调block
     __CFRunLoopDoSource0(); //例如UIKit处理的UIEvent事件

     CheckIfExistMessagesInMainDispatchQueue(); //** dispatch main queue

     __CFRunLoopDoObservers(kCFRunLoopBeforeWaiting); //即将进入休眠,会重绘一次界面
     var wakeUpPort = SleepAndWaitForWakingUpPorts();
     // mach_msg_trap,陷入内核等待匹配的内核mach_msg事件
     // Zzz...
     // Received mach_msg, wake up
     __CFRunLoopDoObservers(kCFRunLoopAfterWaiting);
     // Handle msgs
     if (wakeUpPort == timerPort) {
          __CFRunLoopDoTimers();
     } else if (wakeUpPort == mainDispatchQueuePort) {
          //**当调用dispatch_async(dispatch_get_main_queue(),block)时,libDispatch会向主线程的runloop发送mach_msg消息唤醒runloop,并在这里执行。这里仅限于执行dispatch到主线程的任务,dispatch到其他线程的仍然是libDispatch来处理。
          __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__()
     } else {
          __CFRunLoopDoSource1();  //CADisplayLink是source1的mach_msg触发?
     }
     __CFRunLoopDoBlocks();
} while (!stop
声明:文章版权归原作者所有 部分文章转自互联网 如有侵权请联系 [邮箱地址] 删除

路过

雷人

握手

鲜花

鸡蛋

相关分类

返回顶部