iOS RunLoop(一)概念与构成

status
category
date
summary
slug
icon
tags
password
  • iOS RunLoop(一)概念与构成
  • iOS RunLoop(二)生命周期与运行逻辑
  • iOS RunLoop(三)应用与实践
版本:CF-1153.18
为了学习 RunLoop 的基础知识,本系列在截取源码时省略了很多部分,例如结构体定义、锁的操作、指针的释放等等,省略的代码也非常重要,但是比较影响阅读速度,暂时忽略也并不影响学习整体概念。
第一篇主要介绍 RunLoop 的概念、和线程的关系、相关结构体的含义及构成,主要目的是了解 RunLoop 是什么,以及学习 RunLoop 相关接口的概念。

RunLoop 与线程

RunLoop 是与线程一一对应的,如果线程没有创建或启动 RunLoop,那么线程运行完一次就退出了。RunLoop 赋予了线程“循环”的能力,循环是所有事件驱动系统的本质:如果不退出,就一直循环监听并处理事件。我大一时用命令行窗口实现的贪吃蛇就是如此,游戏本身是一个死循环,蛇每走一步都要进行重复的操作:监听键盘输入控制方向、往前走一步、判断是否吃到食物、判断是否撞墙。
在 iOS 中启动一个 App,正常情况下 main 函数始终没有返回,仿佛进入了一个死循环,原因就是 UIApplication 帮助我们在主线程创建并启动了 RunLoop。

RunLoop 的构成

RunLoop 的结构体定义如下:
可以看到一个 RunLoop 能持有多个 RunLoopMode,如果需要切换 Mode,只能退出 RunLoop 再指定一个 Mode 重新进入。

RunLoopMode

一个 RunLoopMode 又可以持有多个 RunLoopModeItem(Source/Timer/Observer),这样设计的目的主要是为了分隔开不同的 item,让它们能够在各自的“模式”下互不干扰地进行工作。RunLoopMode 的定义如下:
RunLoop 的内容发生变化时,只有当前 Mode 下的 item 都会做出响应。如果想要某个 item 对所有 Mode 的下的事件做出响应,可以把它添加到 commenCodeItems 中,之后 RunLoop 会自动把它们更新到 commonModes 中去。
例如,主线程的 RunLoop 里有两个预设的 Mode:kCFRunLoopDefaultMode 和 UITrackingRunLoopMode,前者是平时默认所处的状态,后者用于追踪 UIScrollView 的滑动状态,它们都已经被包含在 commonModes 中。当我们创建一个 Timer 并加到 DefaultMode 中时,一般情况下 Timer 会得到重复回调并在设置的时间点触发,但如果滑动一个 ScrollView,RunLoop 会将 Mode 切换为 TrackingRunLoopMode,此时 Timer 停止工作,不会回调和计时。如果需要这个 Timer 始终保持工作,可以把它加入到 commonModeItems 中。

RunLoopTimer

在 iOS 中,上层用到的计时器 NSTimer 实际上是通过 CFRunLoopTimer 实现的,它们通过 bridge 互通。另外,performSelector:afterDelay 方法的声明不是在 NSObject 中 而是在 NSRunLoop 中,也暗示该方法是通过 RunLoop 实现的。RunLoopTimer 的定义:
其包含了一个时间长度和一个回调函数指针,进入 RunLoop 时会注册对应的时间点,到达这个时间 RunLoop 就会唤醒并执行回调。Timer 还包含了一个 _tolerance 属性,表示允许唤醒时间的最大误差。例如当前 RunLoop 执行了一个很长的任务,超出了计时器唤醒的最大误差限度,那么这个回调也会被跳过,不会执行。

RunLoopSource

CFRunLoopSource 是循环系统的事件输入源,输入源通常会产生异步事件,然后随着 RunLoop 生命周期的进行不断执行回调。
可以看到有两个特殊的 CFRunLoopSourceContext,一般简称为两个特殊的 source:
  • source0:非基于 port,不能主动触发事件,需要先将其标记为待处理,然后手动唤醒 RunLoop 处理它
  • source1:基于 port,通过内核与其他线程通信,接受并分发系统事件,可以主动唤醒 RunLoop

RunLoopObserver

Observer 允许我们观察 RunLoop 的生命周期和活动通知,并执行相应的回调:
其中 CFOptionFlags 定义了 RunLoop 的生命周期活动:

总结

现在我们知道了 RunLoop 是和线程挂钩的概念,且只有主线程会自动创建并启动 RunLoop。一个 RunLoop 通过它包含的很多 RunLoopMode 来管理资源,每个 RunLoopMode 的内容主要是这些 RunLoopModeItem:
  • RunLoopTimer:计时器,即定时任务的回调
  • RunLoopSource:事件源,即事件的处理
  • RunLoopObserver:观察者,即 RunLoop 生命周期的回调
RunLoop 的结构图示:
notion image
另一张图表示了各个结构的数量对应关系:
notion image
Loading...

© 刘口子 2018-2025