iOS - RunLoop 相关知识点

news/2025/11/26 12:43:29/文章来源:https://www.cnblogs.com/qisheng-blogs/p/19272298

为什么要有 RunLoop?

  • 背景:线程执行完任务就会退出,但主线程(或者一些后台线程等)我们希望它能够一直存在、持续等待事件(触摸、定时器、网络回调等)。

原始的解决方案:

  • 如果写成 while(1) {} 类似的死循环,会出现问题:
    • 线程会持续占用 CPU(忙等待),浪费资源。

🍎给出的答案:

  • 👉 RunLoop —— 让线程在有事件时被唤醒执行,没有事件时进入休眠。
    • 在没有 RunLoop 的情况下,线程要么退出、要么忙等,无法高效等待事件。
    • Apple 的设计是 —— 让线程进入一个由内核管理的 事件循环系统,当有事件发生时唤醒线程,没有事件时进入休眠。
    • 这就是 RunLoop 的核心思想:事件驱动 + 内核唤醒 + 自动调度。

核心概念

本质runloop本质是一个基于 事件驱动 的循环机制,底层依托内核的 mach port 进行等待和消息分发。用于 调度 定时器、输入源和观察者,让线程在“有事活跃、无事休眠”之间高效切换。

核心功能

  1. 保持程序的持续运行(长连接、后台任务等)
  2. 监听 App 中的各种事件(触摸、滑动、定时器事件等)
  3. 自动管理 AutoreleasePool
  4. 控制线程的状态,节省 CPU 资源,提高程序性能

好处:相较于 线程轮询runloop的工作机制效率更高。它允许在闲置时将线程置于睡眠状态,CPU进入低功耗状态,从而节约能源资源。

地位:在 iOS 中,RunLoop 是整个系统事件机制的核心支柱。主线程的 RunLoop 是 UIKit 事件响应、定时器、动画、触摸、AutoreleasePool、GCD 主队列 的共同基础。


组成角色

image

/// CFRunLoop 核心成员struct __CFRunLoop {CFMutableSetRef _commonModes;CFMutableSetRef _commonModeItems;CFRunLoopModeRef _currentMode;CFMutableSetRef _modes;mach_port_t _wakeUpPort;  // 唤醒 RunLoop 的系统端口
};

一、输入源 (Sources)

  • Source0(非端口事件): 用户态事件源,App内部事件,不能自动唤醒 runloop,需要手动 signal。
    • 特点:
      • 不依赖系统内核或端口。
      • RunLoop 不会被系统自动唤醒,必须手动调用 signal + wakeup
      • 常用于线程间通信 或 自定义事件调度
    • 例:
      • performSelector: onThread:
        1. 系统把 selector 封装事件为 source0。
        2. 加入到目标线程 runloop 的 source0 队列。
        3. 内部调用唤醒 signal + wakeup 唤醒 runloop。
          • 如果目标线程 runloop 正在执行,依然等待到下一轮循环的 source0 阶段再执行。
  • Source1(端口事件): 内核级事件源,由RunLoop和内核管理,Mach port驱动。
    • 特点:
      • 依赖系统的端口(mach port),用于接收内核或者其他线程发送的消息。
      • 用于系统级事件(触摸、网络)或者跨线程通信(CFMessagePortCFMachPort)。
      • 当有端口消息到达时,内核通过 mach_msg 唤醒 RunLoop 所在线程。
    • 例:
      • UI事件:触摸、点击(基于 mach port 通知主线程 runloop)
      • 网络事件:Socket 数据到达 → 内核通知 → Source1 被唤醒 → 调用回调处理数据。
      • Port 消息:NSMachPortCFMessagePort 等。

二、定时器 (Timers)

独立于 source 的一种事件类型。

  • 机制:
    • runloop 维护的一组定时器(NSTimer/performSelector:afterDelay:)。
    • 每轮循环时检查定时器的 “下一次触发时间”。
    • 如果到达了触发点,执行对应回调。
    • 若 runloop 处于休眠状态,内核会在最近一个 Timer 到期时唤醒线程。
  • 注意:
    • Timer 属于 runloop 的事件调度机制,不依赖 mach port 消息。

三、观察者 (Observers)

image

监听 RunLoop 状态变化的钩子(CFRunLoopObserver

  • 用途:
    • 监听 runloop 各个阶段(Entry/BeforeTimers/BeforeSources/BeforeWaiting/AfterWaiting/Exit)。
    • 常用于:
      • 性能调试(卡顿监测)
      • 帧率刷新(CADisplayLink 内部机制)
      • 自动管理 AutoreleasePool(系统就在此阶段创建/销毁池子)

四、模式 (Modes)

image

每个 RunLoop 必须且只能运行在一个 Mode 下(Mode 可切换)。
每个 Mode 定义了 RunLoop 本轮循环中要监听哪些事件源(SourcesTimersObservers)。

为什么需要 Mode ?

  • 因为不同场景下需要“隔离事件源”。
  • 比如用户滚动时,RunLoop 会切换到 tracking 模式以屏蔽 default 模式下的定时器。

常用 Mode

标题 描述 应用场景
NSDefaultRunLoopMode 默认模式 普通任务、定时器
UITrackingRunLoopMode UI追踪模式 滚动、拖拽时系统使用
NSRunLoopCommonModes 一种“标记集合”(非真正的Mode) 用来把 Source/Timer 同时加入多个 Mode
GSEventReceiveRunLoopMode 系统底层模式 接收系统级输入事件(触摸、键盘)
kCFRunLoopCommonModes Core Foundation 层关键字 与 NSRunLoopCommonModes 一致
  1. NSDefaultRunLoopMode

    • 主线程默认运行在该模式下。
    • 通过 NSTimerperformSelector:afterDelay: 创建的定时器都会加入这个 Mode
    • 缺点:当用户滚动 UIScrollView 时,RunLoop 会自动切换到 UITrackingRunLoopMode,导致 Default 模式下的 Timer 暂停。
    • 例子
      • Source0: performSelector:onThread:
      • Timer: NSTimerafterDelay:
      • Observer: AutoreleasePool create/drain(注册在 CommonModes 下)
  2. UITrackingRunLoopMode

    • 用户触摸、滚动、拖动页面时,runloop 会临时切换到 tracking 模式。
    • 滚动结束后,runloop 会自动切回 Default 模式。
    • 例子
      • Source1: 触摸 / 滑动事件(基于 Mach port
      • Observer: AutoReleasePool create/drain(注册在 CommonModes 下)
  3. NSRunLoopCommonModes

    • 不是 Mode,而是一个“模式集合标签”

    • 任何被加入到 CommonModesSource/Timer,会同时参与多个 Mode

    • 例子

      • 让某些 NSTimer 同时参与 default + tracking
      NSTimer *timer = [NSTimer timerWithTimeInterval:1 repeats:YES block:^(NSTimer * _Nonnull timer) {NSLog(@"Tick");
      }];
      [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
      
  4. 其他内部 Mode

    • UIInitializationRunLoopMode: App 启动阶段使用(私有)。
    • GSEventReceiveRunLoopModeCoreGraphics 层,用于接收系统级输入事件(触摸、键盘)。
    • kCFRunLoopCommonModes:CFRunLoop 层关键字,等价于 NSRunLoopCommonModes

模式之间的关系与区别

从上述文章看来,UITrackingRunLoopMode 和 GSEventReceiveRunLoopMode 都参与了 UI 事件处理,那他们是否冲突呢?

模式 所属层级 作用 谁在用?
GSEventReceiveRunLoopMode CoreGraphics/CoreAnimation 接收来自内核(Mach Port)的原始触摸、键盘事件 系统私有
UITrackingRunLoopMode UIKit 当用户开始滚动/拖拽时,UIKit 临时切换到此模式来追踪触摸事件 UIKit 控制的住 runloop
[ 内核 mach_msg ]↓
[ CoreGraphics 接收原始触摸事件 ] (GSEventReceiveRunLoopMode)↓
[ UIKit 处理触摸与滚动逻辑 ](UITrackingRunLoopMode)↓
[ App 代码响应事件 ]

从他们的分工与所属不难看出,他们并不冲突,而是事件分发链路的上下层关系。

GSEventReceive 在底层接收输入,UITracking 在上层进行滚动和触摸追踪。


RunLoop 的工作原理

image


线程与 RunLoop

特性 主线程 runloop 子线程 runloop
自动创建
自动启动 ❌需要手动启动
自动管理 Pool
生命周期 app退出 手动退出、线程结束
常见用途 UI事件、主队列任务、动画刷新 后台任务、定时器、网络回调、自定义输入源
  1. 子线程为什么 Timer 不会触法?
    答:子线程没有 runloop 或没有进入循环。timer 依赖于 runloop,需要手动启动。
  1. 为什么 runloop 让线程“有事活跃,无事休眠”?
    答:sleep 阶段阻塞在内核消息等待上,不消耗 CPU

AutoreleasePool 与 RunLoop

AutoreleasePool:内存回收的延迟释放机制

RunLoop:基于事件驱动的循环机制

总体关系RunLoop 在每一轮循环中自动创建和销毁 AutoreleasePool,以此用来管理这一轮产生的 autorelease 对象,确保在循环结束时被及时释放。

线程与 AutoreleasePool 栈

  • 每个线程都有自己的 AutoreleasePool 栈结构(由 runtime 维护),哪怕没有显示写 @autoreleasepool
  • 但是线程启动时栈是空的,只有在执行 autorelease 操作时,系统才会 懒加载创建池页(AutoreleasePoolPage) 来接收对象。

主线程的行为

  • 主线程拥有默认的 RunLoop(由系统在 UIApplicationMain 启动时创建)。
  • 主线程 RunLoopUIKit 注册并托管,含有 pool observer,自动在每轮循环创建/销毁 AutoreleasePool
RunLoop 阶段 行为
Entry 创建新的 AutoreleasePool
BeforeWaiting 销毁旧 Pool 并新建一个空 Pool(防止长时间未释放)
Exit 销毁当前 Pool
  • 因此,主线程在每一轮事件循环结束时,都会清理掉该轮产生的临时对象。

子线程的行为

  • 子线程默认 没有 RunLoop,系统也不会自动为它管理 AutoreleasePool

    • 子线程 RunLoop 默认也没有 pool observer,不会自动管理 autoreleasepool,,因此必须在启动前包一层 @autoreleasepool,否则 RunLoop 循环期间 autorelease 对象不会及时释放, 直到线程退出才清空,可能引发内存峰值或泄漏。
    - (void)startBackgroundThread {NSThread *thread = [[NSThread alloc] initWithBlock:^{@autoreleasepool {[[NSRunLoop currentRunLoop] run];}}];[thread start];
    }
    
  • 但是子线程仍有 Pool 栈结构,只是如果不手动创建 Pool,也没有启动 RunLoopautorelease 对象会延迟到线程结束才被释放。

    • 若希望子线程能够周期性释放对象,有 2 种做法:
      1. 手动添加 @autoreleasepool;
      2. 启动该线程的 RunLoop,让系统周期性创建和销毁 Pool

GCD 与 RunLoop

GCD:线程的“任务调度机制”

RunLoop:线程的“事件循环机制”

总体关系GCD 负责把任务派发到线程,RunLoop 负责让线程保活,并在空闲时处理事件,两者是协同关系。

GCD 与 RunLoop 的底层交互机制

GCDRunLoop 的通信,是通过 Mach port 完成的。

  1. 当调用 dispatch_async(dispatch_get_main_queue(), block);
  2. 系统把 block 放入主队列;
  3. 发送 Mach 消息,通知主线程的 RunLoop;
  4. RunLoop 被唤醒;
  5. RunLoop 调用 _dispatch_main_queue_callback_4CF();
  6. 执行队列里的 GCD block。

所以 RunLoop 驱动 GCD 主队列的执行,没有 RunLoop,主线程就不会被唤醒,主队列的任务也不会被执行。

主线程上的关系

  • 主线程的 RunLoop 是由系统自动创建并运行的(在 UIApplicationMain 内部)。
  • 同时,主线程上也有 GCD 主队列(Main Queue)。

image

当你向主队列派任务时,任务不会立即执行,而是由系统通过 RunLoop 的唤醒机制唤醒主线程,然后在 RunLoopAfterWaiting 阶段执行这些主队列任务。

简言之: 主线程的 GCD 主队列,是通过 RunLoop 驱动执行的。

/// 二者关系:
[ GCD Main Queue ]↓
[ dispatch_async(dispatch_get_main_queue(), ^{ ... }); ]↓
[ 主线程执行任务(依靠 RunLoop 唤醒)]

子线程上的关系

  • 子线程默认没有 RunLoop,因此 GCD 线程池 中的 线程 在执行完任务后就会销毁;
  • 如果想让子线程 “常驻”,就要显示启动 RunLoop,然后 GCD 派发的任务才能在子线程上 持续被处理

参考链接

  • https://cloud.tencent.com/developer/article/1630860
  • https://zhuanlan.zhihu.com/p/467099321

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/977068.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

2025年质量好的机制砂选粉机行业内知名厂家排行榜

2025年质量好的机制砂选粉机行业内知名厂家排行榜行业背景与市场趋势随着我国基础设施建设的持续投入和环保要求的不断提高,机制砂行业迎来了快速发展期。据中国砂石协会最新统计数据显示,2024年我国机制砂市场规模已…

2025年热门的单轴芯导轨行业内口碑厂家排行榜

2025年热门的单轴芯导轨行业内口碑厂家排行榜行业背景与市场趋势单轴芯导轨作为工业自动化领域的关键零部件,近年来随着智能制造、新能源等产业的快速发展,市场需求持续增长。据《2024-2025中国线性传动部件行业白皮…

2025年评价高的护颈AB枕芯厂家最新推荐排行榜

2025年评价高的护颈AB枕芯厂家最新推荐排行榜 行业背景与市场趋势 随着现代人健康意识的提升,护颈枕芯市场近年来呈现快速增长态势。据《2024-2025年中国寝具行业白皮书》数据显示,2024年国内护颈枕芯市场规模已达…

如何安装snac

如何安装snac内容参考:https://www.bandwagonhost.net/12445.html https://blog.example_user.moe/posts/selfhost-snac-activitypub-on-debian-with-nginx/添加一个新账户 使用 adduser 命令创建一个新用户帐户。为新…

2025年质量好的称重包装机厂家推荐及采购参考

2025年质量好的称重包装机厂家推荐及采购参考行业背景与市场趋势随着全球制造业的智能化升级和包装行业的快速发展,称重包装机作为自动化生产线上的关键设备,其市场需求持续增长。据《2024-2029全球包装机械行业市场…

2025年质量好的干选系统选煤设备厂家最新实力排行

2025年质量好的干选系统选煤设备厂家最新实力排行行业背景与市场趋势随着全球能源结构调整和环保要求日益严格,煤炭行业正经历着深刻的转型升级。据中国煤炭工业协会最新数据显示,2024年我国煤炭洗选率已达到78.5%,…

2025年口碑好的污水处理设备热门厂家推荐榜单

2025年口碑好的污水处理设备热门厂家推荐榜单行业背景与市场趋势随着我国环保政策的持续加码和"双碳"目标的深入推进,污水处理设备行业迎来了前所未有的发展机遇。据中国环保产业协会最新数据显示,2024年我…

【日记】第一次听这么多内幕消息哈哈哈(1243 字)

正文培训讲了一天安装麒麟系统,敲 ls, cp, mv, sudo 这种命令…… 真的没问题吗…… 我感觉每次培训都要从很白痴的地方开始讲起。算是玩了一天手机吧。昨天开了中泰的户,总觉得还是有点亏,于是又开始找其他渠道。最…

2025年知名的气相硅橡胶厂家推荐及选择参考

2025年知名的气相硅橡胶厂家推荐及选择参考行业背景与市场趋势气相硅橡胶作为一种高性能有机硅材料,近年来在电子电器、汽车制造、医疗器械、新能源等领域的应用持续扩大。根据《2024-2029年中国有机硅行业市场调研与…

2025年热门的水处理环保设备品牌厂家排行榜

2025年热门的水处理环保设备品牌厂家排行榜行业背景与市场趋势随着全球环保意识的不断提升和各国环保法规的日益严格,水处理环保设备行业迎来了前所未有的发展机遇。根据最新发布的《2024-2029年中国水处理设备行业市…

2025年知名的蜗轮蜗杆升降机最新TOP厂家排名

2025年知名的蜗轮蜗杆升降机最新TOP厂家排名行业背景与市场趋势蜗轮蜗杆升降机作为工业传动领域的关键设备,近年来随着制造业自动化升级和智能制造的推进,市场需求持续增长。据《2024-2025年中国传动设备行业白皮书》…

2025年评价高的抗风工业门厂家最新TOP排行榜

2025年评价高的抗风工业门厂家最新TOP排行榜行业背景与市场趋势随着工业4.0的深入推进和智能制造需求的持续增长,抗风工业门作为工业建筑安全防护的重要设施,其市场需求呈现稳定上升态势。据中国工业门行业协会最新数…

2025年质量好的乘客电梯市场认可度TOP排行榜

2025年质量好的乘客电梯市场认可度TOP排行榜 开篇:行业背景与市场趋势 随着城市化进程的加速和高层建筑的普及,乘客电梯作为现代建筑的核心配套设施,市场需求持续增长。据《2024-2025中国电梯行业白皮书》显示,2…

2025年口碑好的自动点胶机TOP实力厂家推荐榜

2025年口碑好的自动点胶机TOP实力厂家推荐榜行业背景与市场趋势随着智能制造和工业4.0的深入推进,自动点胶机作为精密制造领域的关键设备,市场需求持续增长。据《2024-2029年中国自动点胶机行业市场调研与发展前景分…

Mac安装git

Homebrew 是 macOS 的一个流行的包管理器,类似于 Linux 上的 apt-get。要使用 Homebrew,你可以按照以下步骤操作: 可以使用Homebrew安装git ‌1.安装 Homebrew‌(如果你还没有安装的话): 打开终端,然后粘贴并运…

2025年靠谱的纹织工艺培训高质量教学推荐榜

2025年靠谱的纹织工艺培训高质量教学推荐榜行业背景与市场趋势纹织工艺作为中国传统纺织行业的核心技术之一,近年来随着智能制造和数字化转型的推进,正经历着前所未有的技术革新。根据中国纺织工业联合会最新发布的《…

2025头皮按摩膏品牌推荐:脱发、敏感、修复、滋养首选草本老姜王

在如今琳琅满目的头皮按摩膏市场中,选择一款真正适合自身需求的产品可谓是一道难题。2025年最值得推荐的头皮按摩膏品牌,以其独特的技术优势和良好的用户口碑脱颖而出。每个品牌都有其鲜明的特点,如草本成分、专业医…

2025年评价高的外半圆管厂家最新权威推荐排行榜

2025年评价高的外半圆管厂家最新权威推荐排行榜行业背景与市场趋势随着全球工业化的持续推进和基础设施建设的不断扩张,外半圆管作为关键工业零部件,在石油化工、电力能源、船舶制造等领域的应用日益广泛。据中国机械…

2025年耐用的电火花数控线切割机床优质厂家推荐榜单

2025年耐用的电火花数控线切割机床优质厂家推荐榜单行业背景与市场趋势电火花数控线切割机床作为精密加工领域的关键设备,近年来随着制造业转型升级需求激增而快速发展。根据中国机床工具工业协会最新数据,2024年我国…

2025年口碑好的矿用托辊厂家推荐及选购参考榜

2025年口碑好的矿用托辊厂家推荐及选购参考榜 行业背景与市场趋势 矿用托辊作为输送系统的核心部件,其性能直接影响矿山、煤炭、冶金等行业的输送效率与安全性。据《2024年中国矿山机械行业分析报告》显示,全球矿用…