0%

iOS Runloop解析以及应用

Runloop简介

  顾名思义,从命名上来讲就是一直在循环运行,按照API文旦给的解释是用来处理输入源的,包括触摸、键盘和端口等信息,目的就是接收事件处理,没有就休息等待,想一个APP程序启动之后就有一个对应的Runloop在运行,下面摘抄官方解释(链接)

A NSRunLoop object processes input for sources such as mouse and keyboard events from the window system, NSPort objects, and NSConnection objects. A NSRunLoop object also processes NSTimer events.

不过注意NSRunLoop是非线程安全的,只能被当前对应的线程进行操作,不要在其他线程调用任何改NSRunLoop方法。也处理NSTimer事件,虽然不是输入源,作为一种特殊的输入类型。

Runloop工作原理

  封面图展示的左边为工作过程,右边为内部结构组成。其中包括多组Mode,每个Mode又包含SourceObserverTimer,运行的时候只能在处于一个Mode中,切换需要先退出当前运行Mode再进入指定Mode,下面看看Mode这三个元素

1.Source

属于Set类型,表示事件来源,又分为Source0Source1:

  • Source0,非基于Port,用于处理用户主动触发的事件,如屏幕触摸事件
  • Source1,基于Port,处理内核相关的信息,如IPC就是基于这个处理的。也会分发一些给Source0去处理

2.Observer

观察者,监听状态改变,监听的事件种类有

1
2
3
4
5
6
7
8
9
10
/* Run Loop Observer Activities */
typedef CF_OPTIONS(CFOptionFlags, CFRunLoopActivity) {
kCFRunLoopEntry = (1UL << 0), //即将进入RunLoop
kCFRunLoopBeforeTimers = (1UL << 1),//将处理timer之前
kCFRunLoopBeforeSources = (1UL << 2),//将处理source之前
kCFRunLoopBeforeWaiting = (1UL << 5),//将进入休眠
kCFRunLoopAfterWaiting = (1UL << 6),//休眠中唤醒
kCFRunLoopExit = (1UL << 7), //退出
kCFRunLoopAllActivities = 0x0FFFFFFFU //默认所有
};

3.Timer

为定时器,在Runloop运行的时候会进行计时,然后唤醒指定的操作。

Runloop工作流程图如下:

简单来讲就是一个do-while循环,有输入源就唤醒,没有就处于休眠状态,官方解释链接。具体过程如下:

  1. 通知观察者开始进入Runloop
  2. 通知观察者开始处理Timer事件
  3. 通知观察者将要处理非基于port的事件
  4. 启动准备好的事件
  5. 如果基于port的事件已经准备好,立即启动。并进入步骤9
  6. 通知观察者进入休眠状态
  7. 线程进入休眠直到以下事件出现
    • 基于port的事件源出现
    • 定时器启动
    • 设置的时间已经超时
    • RunLoop被唤醒
  8. 通知观察者线程将被唤醒
  9. 处理已经进入的事件
    • 如果用户自定义的计时器启动,处理事件并重启Runloop。转到第二步
    • 输入源启动,传递消息
    • 如果Runloop被显示唤醒且没有超时,重启Runloop。转到第二步
  10. 通知观察者Runloop已经推出

Runloop应用场景

常见的就是需要线程常驻功能,这也是Runloop存在的意义,保证不退出且不消耗资源。