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.0
                                                      target:self
                                                    selector:@selector(timerFired:)
                                                    userInfo:nil
                                                     repeats: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.mfbz.cn/a/673380.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【再探】设计模式—备忘录模式与解释器模式

备忘录模式是用于保存对象在某个时刻的状态,来实现撤销操作。而解释器模式则是将文本按照定义的文法规则解析成对应的命令。 1 备忘录模式 需求:保存对象在某个时刻的状态,后面可以对该对象实行撤销操作。 1.1 备忘录模式介绍 提供一种状…

Anaconda创建python环境默认C盘,如何修改路径

文章目录 前言解决方案1.找到Anaconda的根目录2. 找到根目录文件夹,右键-属性-安全 测试-重新创建新的python环境 前言 使用 Anaconda创建python环境,默认在C盘。 如何修改到别的路径呢? base环境 是安装 Anaconda是安装的默认环境&#x…

YOLOv8_obb训练流程-原理解析[旋转目标检测理论篇]

在旋转目标检测网络中,换了个顺序,先把训练流程捋一遍,然后再取捋一下测试的流程。由下图的YOLOv8l_obb网络结构图可以看到相对于目标检测网络,旋转目标检测网络只是在Head层不相同,在每个尺度特征层中增加了Angle分支(浅蓝色),通过两个卷积组和一个Conv卷积得到得到通…

隐马尔可夫链

1 马尔可夫链 马尔科夫链(Markov Chain)是一种数学模型,它描述了一系列可能事件的概率,其中每个事件的发生仅依赖于前一个事件的状态。这一特性称为“无记忆性”或“马尔可夫性质”。我将用一个简单的天气预测模型作为例子来解释马…

Docker的网络管理

文章目录 一、Docker容器之间的通信1、直接互联(默认Bridge网络)1.1、Docker安装后默认的网络配置1.2、创建容器后的网络配置1.2.1、首先创建一个容器1.2.2、ip a 列出网卡变化信息1.2.3、查看新建容器后的桥接状态 1.3、容器内安装常见的工具1.4、容器间…

记一次线上数据库连接超时异常问题

最近其他团队的开发人员告知我,我们项目有个feign接口调用失败了。我查看日志发现,其原因是尝试数据库连接超时,30秒内都没有连接成功。 我首先判断可能是网络不稳定,在一定时间内连接不上数据库。我登录到服务器环境看&#xff0…

内网域中NTLM中继那些事儿

0x01 初识NTLM协议 基本概念:NTLM(NT LAN Manager)认证是一种早期的Windows网络身份认证协议。它在Windows系统中用于验证用户的身份,并提供对网络资源的访问控制,它是一种基于Challenge/Response的认证机制。 认证流程 NTLM协议Challenge…

如何使用 DANN 改进神经网络

文章目录 一、说明二、语言模型真的理解语言吗?三、了解分配转变3.1 样本选择偏差3.2 非静止环境3.3 领域适配挑战3.4 概念漂移 四、对领域对抗训练的介绍 一、说明 由于其多功能性,神经网络是大多数现代机器学习管道的主要内容。他们处理非结构化数据的…

mathtype7最新产品密钥激活2024最新

MathType是一款专业的数学公式编辑器,广泛应用于教育、科研和出版等领域。随着在线教育和远程工作的兴起,MathType的使用场景更加广泛,成为教师、学生、研究人员和专业作家必不可少的工具之一。本文将详细介绍MathType的功能特点、操作步骤以…

HTML 总结

HTML 简介 HTML(HyperText MarkupLanguage): 超文本标记语言 超文本 : 普通文本指的是只有文字没有图片 ,视频, 音乐,而超文本就有 标记语言 : 由标签构成的语言 HTML的标签都是预定好的, 如<a> </a> 为超链接 HTML代码直接在浏览器中运行,由浏览器内核进行解…

C++自定义String类

自定义一个String类型,该类包含一个指向字符串的指针和一个统计对象数量的计数器. 代码如下: //string.h #pragma once //String类型 #include <iostream> using namespace std;class String { private:char* m_str;//保存字符串的地址static int num_strings;//创建的对…

Nginx服务的主配置文件及配置举例

Nginx服务的主配置文件 安装Nginx认识Nginx服务全局配置I/O 事件配置HTTP 配置日志格式设定 访问状态统计配置查看Nginx已安装模块修改 nginx.conf 配置文件重启服务&#xff0c;访问测试 基于授权的访问控制准备用户密码认证文件修改 nginx.conf 配置文件重启服务&#xff0c;…

Xcode下载安装

1.Xcode可用版本判断&#xff1a; 2.Xcode下载安装&#xff1a; 方案1:AppStore 下载更新 若方案1失败则 方案2:指定版本Xcode包下载解压安装 苹果下载 3.Xcode命令行工具插件安装 xcode-select --install 备注&#xff1a; xcode_x.x.x.xip(压缩包存在时效性(使用前24h/…

【目录扫描】feroxbuster v2.10.2 字典整合版

# 简介 Feroxbuster是一款强大的目录扫描工具&#xff0c;Feroxbuster的主要功能是基于字典的目录扫描&#xff0c;并且默认使用Seclists字典进行使用&#xff01;并且具有快速和高效的特点&#xff0c;采用了多线程的技术来加快扫描速度。还支持暂停交互式设置等&#xff01;…

从一个猜数游戏开始

标题 一、从源码中学习1.1 源码1.2 运行结果 二、 导入一个trait三、重要源码分析 一、从源码中学习 1.1 源码 一个简单的猜数大小游戏&#xff0c;不集的输入&#xff0c;直到猜测正确时退出。 use rand::Rng; use std::cmp::Ordering; use std::io;fn main() {let secret_…

解锁自动化文档转换:Python-Markdown的魔法

文章目录 解锁自动化文档转换&#xff1a;Python-Markdown的魔法背景Python-Markdown是什么&#xff1f;如何安装Python-Markdown&#xff1f;Python-Markdown库函数使用方法场景应用示例常见问题与解决方案总结 解锁自动化文档转换&#xff1a;Python-Markdown的魔法 背景 在…

【Leetcode每日一题】 动态规划 - 简单多状态 dp 问题 - 买卖股票的最佳时机含冷冻期(难度⭐⭐)(79)

1. 题目解析 题目链接&#xff1a;309. 买卖股票的最佳时机含冷冻期 这个问题的理解其实相当简单&#xff0c;只需看一下示例&#xff0c;基本就能明白其含义了。 2.算法原理 二、算法思路 1. 状态表示 dp[i][0]&#xff1a;表示第 i 天结束后&#xff0c;处于「买入」状态…

总结2024.6.2

最近&#xff0c;还没受到offer&#xff0c;找工作找到自闭。在找工作的过程中&#xff0c;也听到一些面试官问我的职业生涯规划。这也让我陷入了沉思。自从考研结束后&#xff0c;都是被这个社会推着走的。我当初也想过自己要从事什么工作&#xff0c;不过&#xff0c;后面还是…

Mysql常见问题总结

1、MySQL初始化报错 mysqld --initialize --usermysql --console 2024-06-02T15:52:22.645557Z 0 [System] [MY-013169] [Server] D:\installSoft\mysql-8.0.21-winx64\bin\mysqld.exe (mysqld 8.0.21) initializing of server in progress as process 8980 2024-06-02T15:52:2…

向量叉乘的方向

向量叉乘的方向 最近在百度上看到这样一个帖子&#xff1a; 可以根据这个判断是顺时针还是逆时针的 ab的方向&#xff1a;四指由a开始&#xff0c;指向b&#xff0c;拇指的指向就是ab的方向&#xff0c;垂直于a和b所在的平面&#xff1b; ba的方向&#xff1a;四指由b开始&a…