RunLoop小白入门

在这里插入图片描述

核心概念

什么是 RunLoop ?

RunLoop 是 iOS 和 macOS 应用程序框架中的一个核心概念,用于管理线程的事件处理。它可以看作是一个循环,用于持续接收和处理各种事件,如用户输入、定时器、网络事件等。RunLoop 在保持应用程序响应用户交互和系统事件方面起着关键作用。

网络上常见的 source1 具体指什么 ?

其实在苹果的官方文档中是没有这个概念的, 网络上大多数稍有深度的 RunLoop 文章, 基体都会提到 source1 这个概念, source1首次出现已无从考证, 其指代的是基于 Mach 端口的输入源, 两者指的是同一个东西.

在 macOS 和 iOS 中,很多系统事件是通过 Mach 端口传递的。Mach 是底层内核的一部分,提供了进程间通信(IPC)的机制。基于 Mach 端口的输入源(Source1)用于处理这种通信。

苹果用 RunLoop 实现的功能

结合 AutoreleasePool 实现自动清理

在主线程中, 每次RunLoop循环开始和结束时,系统会自动创建和销毁AutoreleasePool。这就像你在每次做完一顿饭后统一清理脏碗碟:

  • RunLoop开始:系统会自动创建一个新的AutoreleasePool,开始处理事件。
  • RunLoop循环中:你可能会创建很多临时对象,这些对象会被添加到当前的AutoreleasePool中。
  • RunLoop结束:系统会自动释放并销毁这个AutoreleasePool,清理所有在这个循环中创建的临时对象。

为什么需要这种机制?
这种机制保证了在每个事件循环结束时,所有临时对象都能被及时释放,避免内存泄漏。如果没有AutoreleasePool,你需要手动管理所有临时对象的释放,增加了代码复杂性和错误的风险。

事件响应

1. 创建 Mach 端口:

系统会为应用程序创建一个 Mach 端口,用于接收来自内核的事件。这些事件可能包括用户输入事件(如触摸、按键)和系统通知等。

2. 将 Mach 端口添加到 RunLoop:

应用程序会将这个 Mach 端口作为 RunLoop 的一个输入源进行注册 (source1)。这是通过创建一个基于端口的 CFRunLoopSourceRef(Core Foundation Run Loop Source)来实现的。

3. 事件的传递与处理:
  • 3.1. 当一个硬件事件(触摸/锁屏/摇晃等)发生后,首先由 IOKit.framework 生成一个 IOHIDEvent 事件并由 SpringBoard 接收;

  • 3.2. SpringBoard 将接收的 IOHIDEvent 事件, 通过 mach port 转发给对应的 App 进程;

  • 3.3. 应用进程中的 Source1 被触发后,调用 __IOHIDEventSystemClientQueueCallback()。这个回调函数进一步调用 _UIApplicationHandleEventQueue() 进行应用内部的事件分发;

  • 3.4. _UIApplicationHandleEventQueue() 将 IOHIDEvent 事件转换成 UIEvent 事件进行处理或分发,其中包括触摸事件的处理(如 touchesBegan/Move/End/Cancel 事件)、按钮点击事件、手势识别(UIGestureRecognizer)等;

手势识别

当上面的 _UIApplicationHandleEventQueue() 识别了一个手势时,其首先会调用 Cancel 将当前的 touchesBegin/Move/End 系列回调打断。随后系统将对应的 UIGestureRecognizer 标记为待处理。

苹果注册了一个 Observer 监测 BeforeWaiting (Loop即将进入休眠) 事件,这个Observer的回调函数是 _UIGestureRecognizerUpdateObserver(),其内部会获取所有刚被标记为待处理的 GestureRecognizer,并执行GestureRecognizer的回调。

界面更新

当在操作 UI 时,比如改变了 Frame、更新了 UIView/CALayer 的层次时,或者手动调用了 UIView/CALayer 的 setNeedsLayout/setNeedsDisplay方法后,这个 UIView/CALayer 就被标记为待处理,并被提交到一个全局的容器去。

苹果注册了一个 Observer 监听 BeforeWaiting(即将进入休眠) 和 Exit (即将退出Loop) 事件,回调去执行一个很长的函数:
_ZN2CA11Transaction17observer_callbackEP19__CFRunLoopObservermPv()。这个函数里会遍历所有待处理的 UIView/CAlayer 以执行实际的绘制和调整,并更新 UI 界面。

定时器

在 iOS 中,RunLoop 和定时器(NSTimerCADisplayLink)有着密切的关系。定时器依赖于 RunLoop 来触发回调函数。

NSTimer 和 RunLoop
工作机制

NSTimer 是一个基于时间间隔的触发器,用于在指定的时间间隔之后向目标对象发送消息。它依赖于 RunLoop 来定期检查和触发, NSTimer 其实就是 CFRunLoopTimerRef,他们之间是 toll-free bridged 的。

  1. 创建定时器

    NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:1.0target:selfselector:@selector(timerFired:)userInfo:nilrepeats:YES];
    
  2. 添加到 RunLoop
    当你使用 scheduledTimerWithTimeInterval:target:selector:userInfo:repeats: 方法创建定时器时,它会自动添加到当前线程的默认 RunLoop 模式中。你也可以手动将 NSTimer 添加到 RunLoop 中:

    [[NSRunLoop mainRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
    
  3. RunLoop 处理定时器
    RunLoop 每次循环时会检查定时器的触发时间。如果定时器的触发时间已到或已过,RunLoop 会触发定时器的回调方法(例如 timerFired:)。

RunLoop 模式对定时器的影响
  • 默认模式 (NSDefaultRunLoopMode):通常用于普通的事件处理。如果 NSTimer 被添加到此模式中,当用户进行滚动操作(导致 RunLoop 切换到 UITrackingRunLoopMode)时,定时器将暂停。
  • 通用模式 (NSRunLoopCommonModes):可以确保 NSTimer 在不同的 RunLoop 模式下都能触发。例如,在滚动视图时,RunLoop 会切换到 UITrackingRunLoopMode,如果定时器添加到通用模式,它仍然会触发。
CADisplayLink 和 RunLoop

CADisplayLink 是一个特殊的定时器,与屏幕刷新率同步,通常用于动画。

  1. 创建和添加 CADisplayLink

    CADisplayLink *displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(displayLinkFired:)];
    [displayLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
    
  2. 屏幕刷新同步
    CADisplayLink 会在屏幕每次刷新时调用其目标对象的选择器方法。屏幕通常每秒刷新60次(即60Hz),因此 CADisplayLink 的回调方法也会以相同的频率调用。

  3. 处理动画
    在回调方法中,可以更新动画状态或执行其他需要在每帧更新的操作。由于它与屏幕刷新率同步,CADisplayLink 非常适合实现平滑的动画。

RunLoop 模式对 CADisplayLink 的影响

NSTimer 类似,如果 CADisplayLink 被添加到默认模式,则在滚动视图时可能会暂停。为确保它在滚动期间也能触发,可以将它添加到通用模式:

[displayLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes];

PerformSelecter

在 iOS 中,RunLoop 和 performSelector 方法之间的关系主要体现在线程间通信和延迟执行这两个方面。RunLoop 负责调度 performSelector 方法的执行时机,确保方法在合适的时机被调用。

关于GCD

GCD 的绝大多数实现并不依赖于 RunLoop,它们是两个独立的机制,各自有不同的应用场景和实现方式。
但是, GCD 提供的某些接口也用到了 RunLoop, 例如 dispatch_async(), 当调用 dispatch_async(dispatch_get_main_queue(), block) 时,libDispatch 会向主线程的 RunLoop 发送消息,RunLoop会被唤醒,并从消息中取得这个 block,并在回调 CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE() 里执行这个 block。但这个逻辑仅限于 dispatch 到主线程,dispatch 到其他线程仍然是由 libDispatch 处理的。

关于网络请求


RunLoop 的实际应用举例

ReactNative创建常驻JS线程

AFNetworking创建后台常驻线程接受回调任务

+ (void)networkRequestThreadEntryPoint:(id)__unused object {@autoreleasepool {[[NSThread currentThread] setName:@"AFNetworking"];NSRunLoop *runLoop = [NSRunLoop currentRunLoop];[runLoop addPort:[NSMachPort port] forMode:NSDefaultRunLoopMode];[runLoop run];}
}

AsyncDisplayKit在主线程的 RunLoop 中添加一个 Observer

ASDK 仿照 QuartzCore/UIKit 框架的模式,实现了一套类似的界面更新的机制:即在主线程的 RunLoop 中添加一个 Observer,监听了 kCFRunLoopBeforeWaiting 和 kCFRunLoopExit 事件,在收到回调时,遍历所有之前放入队列的待处理的任务,然后一一执行。

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

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

相关文章

系统与软件工程软件测试过程

系统与软件工程 软件测试 测试过程 ;对应的国标是GB/T 38634.4 2020 ,该标准的范围规定适应用于治理、管理和实施任何组织,项目或较小规模测试活动的软件测试的测试过程,定义了软件测试通用过程,给出了描述过程的支持信息图表。 一 术语和定义 1.1实测…

宏基础使用实践

文章目录 1.宏变量2.条件宏 1.宏变量 2.条件宏 #include <iostream> #define aa 30 #define version 2using namespace std;/** 1.宏变量* 2.条件宏* */int main() {cout << aa << endl;#if version > 1cout<< "升级版本"<<endl;…

力扣173题:二叉搜索树迭代器(含模拟面试)

❤️❤️❤️ 欢迎来到我的博客。希望您能在这里找到既有价值又有趣的内容&#xff0c;和我一起探索、学习和成长。欢迎评论区畅所欲言、享受知识的乐趣&#xff01; 推荐&#xff1a;数据分析螺丝钉的首页 关注微信公众号 数据分析螺丝钉 免费领取价值万元的python/java/商业…

Luminus推出新型高性能 UV-A LED

​Luminus Devices推出的SST-08H-UV&#xff0c;作为SST-08-UV的升级版&#xff0c;以其独特的高功率UV-A LED系列&#xff0c;犹如一道璀璨的光束&#xff0c;照亮了众多领域。这款LED的卓越之处在于&#xff0c;它巧妙地利用了365nm、385nm、395nm和405nm的峰值波长选项&…

TS中never类型的妙用

在 TypeScript&#xff08;TS&#xff09;中&#xff0c;never 类型是一个特殊的类型&#xff0c;它表示的是那些永不存在的值的类型。这听起来可能有点抽象&#xff0c;但实际上它在一些场景中非常有用。以下是 never 类型在 TypeScript 中的一些妙用&#xff1a; 表示函数永远…

使用System-Verilog实现FPGA基于DE2-115开发板驱动HC_SR04超声波测距模块|集成蜂鸣器,led和vga提示功能

文章目录 前言一、实验原理1.1 传感器概述&#xff1a;1.2 传感器引脚1.3 传感器工作原理1.4 整体测距原理及编写思路 二、System-Verilog文件2.1 时钟分频&#xff08;1&#xff09;clk_div.sv2.2 超声波测距&#xff08;1&#xff09;hc_sr_trig.sv&#xff08;2&#xff09;…

C# 语言类型(三)—数组/枚举类型/结构体

总目录 C# 语法总目录 参考链接&#xff1a; C#语法系列:C# 语言类型(一)—预定义类型值之数值类型 C#语法系列:C# 语言类型(二)—预定义类型之字符串及字符类型简述 C#语法系列:C# 语言类型(三)—数组/枚举类型/结构体 C#语法系列:C# 语言类型(四)—传递参数及其修饰符 C#语法…

比较两台计算机上的LabVIEW、工具包及驱动程序的一致性

比较两台计算机上的LabVIEW、工具包及驱动程序是否相同&#xff0c;可以通过以下步骤实现&#xff1a; 1. 检查LabVIEW版本 方法一&#xff1a;在LabVIEW中查看版本信息 步骤&#xff1a; 打开LabVIEW。点击菜单栏的 Help > About LabVIEW。记录显示的LabVIEW版本号和许可…

汽车数据应用构想(二)

一直说数据价值场景&#xff0c;啥叫有价值&#xff1f;啥样的场景有价值&#xff1f;按互联网的价值观来看&#xff0c;用户的高频需求就是价值。用户也许不会付费&#xff0c;但只要他天天用&#xff0c;那就是流量&#xff0c;就是用户黏性&#xff0c;就是价值&#xff01;…

力扣1 两数之和

给定一个整数数组 nums 和一个整数目标值 target&#xff0c;请你在该数组中找出 和为目标值 target 的那 两个 整数&#xff0c;并返回它们的数组下标。 你可以假设每种输入只会对应一个答案。但是&#xff0c;数组中同一个元素在答案里不能重复出现。 你可以按任意顺序返回…

阿贝云:免费虚拟主机和免费云服务器评测

阿贝云是一家知名的云服务提供商&#xff0c;提供免费虚拟主机和免费云服务器等服务。在今天的评测中&#xff0c;我们将对阿贝云的免费虚拟主机和免费云服务器进行详细的试用和评测。 首先&#xff0c;让我们来看看阿贝云的免费虚拟主机服务。阿贝云的免费虚拟主机提供稳定可靠…

方法重写

自学python如何成为大佬(目录):https://blog.csdn.net/weixin_67859959/article/details/139049996?spm1001.2014.3001.5501 基类的成员都会被派生类继承&#xff0c;当基类中的某个方法不完全适用于派生类时&#xff0c;就需要在派生类中重写父类的这个方法&#xff0c;这和…

HALCON飞拍贴片机框架程序——硬件介绍

本专栏主要讲解三头贴片机框架程序&#xff0c;包括硬件介绍和软件代码。硬件主要为视觉部分&#xff0c;软件为视觉检测代码部分。贴片机的机械硬件不做介绍。 具体设备运行视频可以搜索博主抖Y&#xff1a;“伶俐科技”观看。 贴片机硬件如下图分为三个部分&#xff0c;第一…

Go 语言中的日期与时间

在文章中&#xff0c;我们将深入探讨 Go 语言中日期和时间的处理。Go 提供了丰富的内置支持&#xff0c;通过 time 包&#xff0c;可以方便地进行时间的表示、格式化、计算以及比较。 文章目录 1、Go 语言中的日期时间介包介绍2、Go 语言中的日期时间介包的使用2.1、导入时间包…

网络安全等级保护,三级等保技术建议书(word原件获取)

1信息系统详细设计方案 1.1安全建设需求分析 1.1.1网络结构安全 1.1.2边界安全风险与需求分析 1.1.3运维风险需求分析 1.1.4关键服务器管理风险分析 1.1.5关键服务器用户操作管理风险分析 1.1.6数据库敏感数据运维风险分析 1.1.7“人机”运维操作行为风险综合分析 1.2…

Java数据结构与算法(有向图)

前言 有向图&#xff08;Directed Graph&#xff09;是一种由顶点和有方向的边组成的图数据结构。 实现原理 使用邻接表表示法实现有向图相对简单明了&#xff0c;步骤也相对简单。 1:首先创建有向图 2.创建顶点 3.顶点间创建边 具体代码实现 package test13;import ja…

Android bw_costly_<iface>链

测试时关注到bw_costly_链 因为和iface有关。猜测这个链是动态生成的。 开关数据业务测试&#xff0c;果然关闭数据业务后&#xff0c;bw_OUTPUT中不再会调用bw_costly_rmnet_data3&#xff0c;也没有bw_costly_rmnet_data3这个链了。 再次打开数据业务后出现了bw_costly_rmnet…

llvm 3.5 源码分析 clang for x86 002 之鸟瞰编译流程

0. 目标 debug的方式挖掘 clang 编译c文件的概述过程 1&#xff0c;示例源文件 summm.c int addd(int a, int b) {return ab; } 2&#xff0c;编译过程 $ clang -fPIE summm.c -c -o summm.o DEBUG: gdb clang set args -fPIE summm.c -c -o summm.…

【C语言】字符串逆序

(来源&#xff1a;牛客网) 题目&#xff1a; 将一个字符串str的内容颠倒过来&#xff0c;并输出。 数据范围&#xff1a;1≤len(str)≤10000 输入描述: 输入一个字符串&#xff0c;可以有空格 输出描述: 输出逆序的字符串 示例1 输入 I am a student 输出 tneduts…

Python 数仓建模

在Python中进行数据仓库&#xff08;Data Warehouse, 通常简称为数仓&#xff09;建模通常涉及到多个步骤&#xff0c;包括数据抽取&#xff08;Extract&#xff09;、转换&#xff08;Transform&#xff09;、加载&#xff08;Load&#xff0c;即ETL过程&#xff09;&#xff…