做电商网站要服务器吗/西安seo全网营销
假设你的项目中有关tableView,然后还有一个定时器timer在执行,定时器代码如下:
var num = 0override func viewDidLoad() {super.viewDidLoad()let timer = Timer(timeInterval: 1,target: self,selector: #selector(self.run),userInfo: nil,repeats: true)RunLoop.current.add(timer, forMode: .default)}@objc func run() {num += 1print(Thread.current ,num)Thread.sleep(forTimeInterval: 3)}
当你滚动tableView时,你会发现timer定时器会停止,当停止滚动tableView,timer定时器会继续进行。这是什么原因呢?
如果学过线程,你会知道:主线程的优先级是最高的,主线程也叫UI线程,也就是说UI事件必须在主线程中进行,因此在iOS中,UI事件会优先进行。
什么是Runloop?
Runloop是一种事件循环机制,用来循环的处理线程中的事件,当Runloop启动时,如果线程中有事件,它就会调用方法来处理该事件,如果没有事件,就会进入休眠,等该线程中有事件需要处理时才会被唤醒。
线程和Runloop的关系
线程和Runloop是一一对应的,它们的关系保存在一个全局的Dictionary中,其中线程是Key,Runloop是Value,对于主线程中的Runloop是在程序启动时自动创建并启动,而其它子线程的Runloop是懒加载的,也就是说,只有子线程有任务需要被执行时Runloop才会创建并启动。
Runloop的功能
Runloop的功能:
- 线程保活,Runloop会在线程中没有任务时让线程进入休眠而不会退出,比如保活主线程,使得应用程序不会退出。
- 负责监听事件,如网络事件,计时器事件,触摸事件
- 渲染UI,一次Runloop循环,需要渲染屏幕上所有变化的像素点
- 节省CPU开销,让程序该休息时休息
Runloop的基本组成
输入源
输入源(Input Source)用于处理异步事件,比如用户交互事件,网络事件等,Runloop运行时,会检查当前线程是否有输入源需要处理,如果有会立即处理。
输入源也可以分为两种source:source0和source1,其中source1是基于port的系统内核事件,可以主动唤醒runloop,在底层是通过Dictionary的Value来存储的,其中Key是machport。而source0是不基于port的,是应用程序主动触发的事件(如:按钮点击触发事件),不会主动唤醒runloop。
如:当我们点击按钮时,触发的事件会被包装成Event,Event通过machport机制告诉source1,source1主动唤醒runloop,然后将事件Event分发给Source0,然后由Source0来处理。
定时器源
定时执行的任务,如NSTimer,Runloop会定期检测定时器,到达时间执行相应操作。
观察者
用于监听Runloop的状态,基本状态如下:
kCFRunloopEntry (runloop准备启动)
kCFRunloopBeforeTimers (通知观察者,runloop将要对Timer的一些相关事件进行处理了)
kCFRunloopBeforeSources (将要处理一些Sources事件)
kCFRunloopBeforeWaiting( 即将要发生用户态到内核态的切换 用户态 —> 内核态)没事做进入内核态避免资源浪费,即:即将进入休眠。
kCFRunloopAfterWaiting (内核态—转—>用户态)即将被唤醒
kCFRunloopExit (runloop退出通知)
Runloop的几种模式
Runloop主要分为以下几种模式:
NSDefaultRunloopMode:默认模式,处理大多数应用事件,比如Timer定时器事件,网络事件等。
NSRunloopCommonModes:常用模式,允许 RunLoop 同时处理多种事件类型。使用场景包括当用户滚动 UIScrollView 时仍能处理定时器事件。
UITrackingRunloopMode:界面追踪模式,处理UI事件,比如滚动tableView时,保证不受其它Mode影响。
UIInitializationRunLoopMode :在刚启动App时第进入的第一个Mode,启动完成后就不再使用
GSEventReceiveRunLoopMode :接受系统事件的内部Mode
这里可以发现,上面我们的timer添加在default模式下,而tableView的滚动是在Tracking模式下的,所以当tableView滚动时不受其它Mode影响,所以timer定时器事件停止执行,而停止滚动tableView,Runloop切换到default模式,正常处理Timer事件。
如果timer添加在common模式下,timer事件不会受tabelView滚动影响,因为tableView滚动时,在Tracking模式下,可以让标记为"common"的事件继续进行。
如果timer添加在Tracking模式下,当滚动tableView时,timer方法执行,当tableView滚动停止,方法不执行。
阻塞
在上面的讲解中,当定时器设置成common模式,UI事件(tableView滚动)进行时,timer事件也会进行,但它们只是看上去是同时进行,实际上无论Mode怎么变化,它始终都是在一个线程上循环往复。
在iOS开发中,有一个非常重要的原则:永远不能阻塞主线程。因此你的timer事件中不能出现耗时操作,比如改成这样,你会发现你的UI界面会卡顿:
@objc func run() {num += 1print(Thread.current ,num)Thread.sleep(forTimeInterval: 3)//让当前线程休眠
}
Runloop实现的功能
1.自动释放池
自动释放池(AutoreleasePool)的创建、释放、销毁时机如下:
- kCFRunLoopEntry; // 进入runloop之前,创建一个自动释放池
- kCFRunLoopBeforeWaiting; // 休眠之前,销毁自动释放池,创建一个新的自动释放池
- kCFRunLoopExit; // 退出runloop之前,销毁自动释放池
2.硬件事件响应
当一个硬件事件(触摸/锁屏/摇晃等)发生后,首先由 IOKit.framework 生成一个 IOHIDEvent 事件并由 SpringBoard 接收。SpringBoard是iOS的系统进程,接收按键(锁屏/静音等)。
然后,SpringBoard 通过 mach_port 将事件传递给目标 App 的进程。此时App 进程中的 RunLoop 会监听来自系统的这些事件。当事件到达时,RunLoop 中注册的 Source1 事件源被触发,唤醒 RunLoop,并执行回调来处理这些事件。
事件进入应用进程后, _UIApplicationHandleEventQueue() 会把 IOHIDEvent 处理并包装成 UIEvent 进行处理或分发,其中包括识别 UIGesture/处理屏幕旋转/发送给 UIWindow 等。通常事件比如 UIButton 点击、touchesBegin/Move/End/Cancel 事件都是在这个回调中完成的。
3.手势识别
当上面的 _UIApplicationHandleEventQueue() 识别了一个手势时,其首先会调用 Cancel 将当前的 touchesBegin/Move/End 系列回调打断。随后系统将对应的 UIGestureRecognizer 标记为待处理。苹果注册了一个 Runloop的Observer 监测 BeforeWaiting (Loop即将进入休眠) 事件,这个Observer的回调函数是 _UIGestureRecognizerUpdateObserver(),其内部会获取所有刚被标记为待处理的 GestureRecognizer,并执行GestureRecognizer的回调。当有 UIGestureRecognizer 的变化(创建/销毁/状态改变)时,这个回调都会进行相应处理。
这里可以发现:手势识别是在Runloop即将进入休眠的时候进行处理的,这样保证了手势识别的优先级比较高。
4.界面更新
当在操作 UI 时,比如改变了 Frame、更新了 UIView/CALayer 的层次时,或者手动调用了 UIView/CALayer 的 setNeedsLayout/setNeedsDisplay方法后,这个 UIView/CALayer 就被标记为待处理,并被提交到一个全局的容器去。苹果注册了一个 Runloop的Observer 监听BeforeWaiting(即将进入休眠) 和 Exit (即将退出Loop) 事件,回调去执行一个很长的函数:_ZN2CA11Transaction17observer_callbackEP19__CFRunLoopObservermPv()。这个函数里会遍历所有待处理的 UIView/CAlayer 以执行实际的绘制和调整,并更新 UI 界面。
界面更新是在Runloop进入休眠前进行的,这样可以避免用户交互时立即刷新页面。
5.定时器
• NSTimer 是基于 RunLoop 的定时器,底层实现为 CFRunLoopTimerRef。当你创建一个 NSTimer 并将其添加到 RunLoop 中时,RunLoop 会为定时器注册好未来的触发时间点。
• 定时器回调并不总是会在非常准确的时间点触发,因为 RunLoop 会对定时器进行一些优化。定时器有一个 tolerance 参数,允许指定触发时间的最大误差。这样可以在保证性能的前提下,避免系统资源的浪费。
如果在某个时间点执行了一个较长的任务,RunLoop 可能会错过该时间点,直接跳到下一个时间点,而不会延后执行。例如,如果 NSTimer 设置为每 10 秒触发一次,但是某次因为执行长时间任务导致错过了 10:00 的触发点,那么定时器会直接在下一个 10:10 的时间点触发。
监听Runloop
如果我们想知道Runloop何时开始,何时结束,可以通过Observer监听Runloop.
如果你只想监听Runloop的某一个状态(比如即将进入休眠),可以如下创建:
// 获取当前的 Runlooplet runloop = CFRunLoopGetCurrent()// 需要监听 Runloop 的哪个状态let activities = CFRunLoopActivity.beforeWaiting.rawValue// 创建 Runloop 观察者let observer = CFRunLoopObserverCreateWithHandler(nil, activities, true, 0) { [weak self] (ob, ac) in。。。。//这里写监听到Runloop某种状态后执行的操作}}// 注册 Runloop 观察者CFRunLoopAddObserver(runloop, observer, .defaultMode)
如果要监听所有状态:
enum RunloopError: Error {case canNotCreate
} do {let block = { (ob: CFRunLoopObserver?, ac: CFRunLoopActivity) inif ac == .entry {print("进入 Runloop")}else if ac == .beforeTimers {print("即将处理 Timer 事件")}else if ac == .beforeSources {print("即将处理 Source 事件")}else if ac == .beforeWaiting {print("Runloop 即将休眠")}else if ac == .afterWaiting {print("Runloop 被唤醒")}else if ac == .exit {print("退出 Runloop")}}let ob = try createRunloopObserver(block: block)CFRunLoopAddObserver(CFRunLoopGetCurrent(), ob, .defaultMode)}catch RunloopError.canNotCreate {print("runloop 观察者创建失败")}catch {}
}fileprivate func createRunloopObserver(block: @escaping (CFRunLoopObserver?, CFRunLoopActivity) -> Void) throws -> CFRunLoopObserver {
//创建监听所有状态的观察者let ob = CFRunLoopObserverCreateWithHandler(kCFAllocatorDefault, CFRunLoopActivity.allActivities.rawValue, true, 0, block)guard let observer = ob else {throw RunloopError.canNotCreate}return observer}
}
Runloop的应用
线程保活
当子线程执行完任务后,子线程会被销毁,而频繁的线程创建和销毁会导致资源的浪费,所有我们在然后在开启子线程后保证子线程永远活着,这时候就需要常驻线程,即:给线程开启一个Runloop。
优化卡顿
在日常开发中,如果我们要加载一个tableView,一般分两部分进行处理:
1.在子线程中处理cell中呈现的数据资源,其中包括网络请求、数据解析、构造模型等等。
2.模型数组准备完毕,在主线程中刷新tableView,使用模型数据填充cell。
这个思路看似很完美,其实还是会有问题,就是如果第二步,也就是使用模型数据填充cell时十分耗时,怎么办?
简单来说,就是:前面讲Runloop功能时,有一点是渲染UI,假设我们在滑动tableView,这时会触发屏幕上的UI变化,而UI变化会触发Cell的复用和渲染,但其实,Cell的渲染是一个是否耗时的操作,这样就会导致Runloop循环一次的时间变长,造成UI卡顿。这个问题该如何优化呢?
解决思路:将Cell的渲染操作剥离出来。
具体过程如下:
1.用一个block数组,存放渲染Cell的代码
2.在cellForRowAtIndexPath代理方法中直接返回cell。
3.监听Runloop,在即将进入休眠阶段取出block数组中的代码进行执行。
简单来说,就是利用runloop的休眠时间来处理Cell的渲染操作。
参考:
https://github.com/miaoqiu/RunLoop?tab=readme-ov-file#按照官方文档source的分类
https://github.com/tianziyao/Runloop
iOS--RunLoop原理_ios 定时器与runloop-CSDN博客
Runloop解析_objective-c runloop-CSDN博客
相关文章:

Runloop
假设你的项目中有关tableView,然后还有一个定时器timer在执行,定时器代码如下: var num 0override func viewDidLoad() {super.viewDidLoad()let timer Timer(timeInterval: 1,target: self,selector: #selector(self.run),userInfo: nil,r…...

SpringBoot的Bean类三种注入方式(附带LomBok注入)
SpringBoot的Bean类三种注入方式(附带LomBok注入) 在 Spring Boot 中,Bean 的注入方式主要包括构造函数注入(Constructor Injection)、字段注入(Field Injection)以及 Setter 方法注入…...

开源向量数据库介绍说明
开源向量数据库 Milvus 特点:分布式、高性能,支持亿级向量检索。 支持的数据类型:文本、图像、音频、视频等。 使用场景:推荐系统、语义搜索、图像搜索。 数据存储后端:支持多种后端,如 SQLite、MySQL、Pos…...

【前端】深度解析 JavaScript 中的 new 关键字与构造函数
博客主页: [小ᶻ☡꙳ᵃⁱᵍᶜ꙳] 本文专栏: 前端 文章目录 💯前言💯构造函数的核心特性💯new 关键字的执行机制💯实例代码与详细解析代码示例代码逐步解析 💯new 的内部执行模拟执行过程的详细解析 &am…...

2024年华中杯数学建模C题基于光纤传感器的平面曲线重建算法建模解题全过程文档及程序
2024年华中杯数学建模 C题 基于光纤传感器的平面曲线重建算法建模 原题再现 光纤传感技术是伴随着光纤及光通信技术发展起来的一种新型传感器技术。它是以光波为传感信号、光纤为传输载体来感知外界环境中的信号,其基本原理是当外界环境参数发生变化时,…...

使用 `typing_extensions.TypeAlias` 简化类型定义:初学者指南
使用 typing_extensions.TypeAlias 简化类型定义:初学者指南 什么是 TypeAlias?安装 typing_extensions示例代码:如何使用 TypeAlias示例 1:为简单类型定义别名示例 2:为复杂类型定义别名示例 3:结合 Union…...

如何快速批量把 PDF 转为 JPG 或其它常见图像格式?
在某些特定场景下,将 PDF 转换为 JPG 图片格式却具有不可忽视的优势。例如,当我们需要在不支持 PDF 查看的设备或软件中展示文档内容时,JPG 图片能够轻松被识别和打开;此外,对于一些网络分享或社交媒体发布的需求&…...

如何在组织中塑造和强化绩效文化?
在组织中塑造和强化绩效文化是一个系统性的工程。 一、明确绩效目标与期望 设定清晰目标 组织应根据自身战略规划,将长期目标分解为具体、可衡量、可实现、相关联、有时限(SMART)的短期和中期绩效目标。例如,一家连锁餐饮企业的…...

OllyDbg、CE简单介绍
基础知识: 想要破解软件,需要一些基础知识: 文件格式:Windows对应PE、Linux对应ELF、IOS对应Mash-0。文件格式是指操作系统规定的每个段(代码段、数据段、堆、栈)的大小、顺序等信息。 汇编语言࿱…...

Python函数——函数的返回值定义语法
一、引言 在Python中,函数的返回值是其核心功能之一,它使得函数能够将计算结果传递给调用者,进而推动程序的逻辑和功能实现。理解和掌握函数的返回值语法,不仅能够提高代码的模块化和可读性,还能使程序更加高效和灵活…...

【Pandas】pandas isna
Pandas2.2 General Top-level missing data 方法描述isna(obj)用于检测数据中的缺失值isnull(obj)用于检测数据中的缺失值notna(obj)用于检测数据中的非缺失值notnull(obj)用于检测数据中的非缺失值 pandas.isna() pandas.isna() 是 Pandas 库中的一个函数,用于…...

mysql 数据库表的大小
mysql 数据库表的大小 Mysql 查看数据库各个表占用空间 mysql如何查看数据库所有表大小 在MySQL中,要查看数据库所有表的大小,可以使用以下方法: 方法一:使用information_schema数据库 首先,通过命令行或图形界面…...

(6)JS-Clipper2之ClipperOffset
1. 描述 ClipperOffset类封装了对打开路径和关闭路径进行偏移(膨胀/收缩)的过程。 这个类取代了现在已弃用的OffsetPaths函数,该函数不太灵活。可以使用不同的偏移量(增量)多次调用Execute方法,而不必重新分配路径。现在可以在一次操作中对开放和封闭路…...

如何在Ubuntu中利用repo和git地址下载获取imx6ull的BSP
01-设置git的用户名和邮箱 git config --global user.name "suwenhao" git config --global user.email "2487872782qq.com"这里不设置的话后面在第5步的repo配置中还是会要求输入,而且以后进行相关操作都要输入,不妨现在就进行配置…...

Ruby On Rails 笔记5——常用验证下
3.Validation Options 3.1 :allow_nil 当验证值为nil时:allow_nil选项会跳过验证 class Coffee < ApplicationRecordvalidates :size, inclusion: { in: %w(small medium large),message: "%{value} is not a valid size" }, allow_nil: true end irb> Cof…...

JS听到了因果的回响
这是我学习JS的第11天了,,,我现在赶着周末学JS,然后还有二十多天就期末了呵呵呵。。。 图片切换模块 思路分析: 这是实现的代码,建议还是把不同的变量定义出来比较合适: //获取三个盒子// 小盒…...

【高中生讲机器学习】28. 集成学习之 Bagging 随机森林!
创建时间:2024-12-09 首发时间:2024-12-09 最后编辑时间:2024-12-09 作者:Geeker_LStar 嘿嘿,你好呀!我又来啦~~ 前面我们讲完了集成学习之 Boooooosting,这篇我们来看看集成学习的另一个分支…...

硬件设计 | Altium Designer软件PCB规则设置
基于Altium Designer(24.9.1)版本 嘉立创PCB工艺加工能力范围说明-嘉立创PCB打样专业工厂-线路板打样 规则参考-嘉立创 注意事项 1.每次设置完规则参数都要点击应用保存 2.每次创建PCB,都要设置好参数 3.可以设置默认规则,将…...

【Elasticsearch】实现用户行为分析
🧑 博主简介:CSDN博客专家,历代文学网(PC端可以访问:https://literature.sinhy.com/#/literature?__c1000,移动端可微信小程序搜索“历代文学”)总架构师,15年工作经验,…...

python字符串处理基础操作总结
1.去掉空格或者特殊符号 input_str.strip() #去掉所有空格 input_str.lstrip() #去掉左边空格 input_str.rstrip() #去掉右边空格 def print_hi():input_str 今天天气不错,风和日丽 out input_str.strip()print(input_str)print(out)if __name__ __main__:print…...

电子商务人工智能指南 6/6 - 人工智能生成的产品图像
介绍 81% 的零售业高管表示, AI 至少在其组织中发挥了中等至完全的作用。然而,78% 的受访零售业高管表示,很难跟上不断发展的 AI 格局。 近年来,电子商务团队加快了适应新客户偏好和创造卓越数字购物体验的需求。采用 AI 不再是一…...

【论文阅读】相似误差订正方法在风电短期风速预报中的应用研究
文章目录 概述:摘要1. 引言2. 相似误差订正算法(核心)3. 订正实验3.1 相似因子选取3.2 相似样本数试验3.3 时间窗时长实验 4. 订正结果分析4.1 评估指标对比4.2 风速曲线对比4.3 分风速段订正效果评估4.4 风速频率统计 5. 结论与讨论 概述&am…...

贪心算法 - 学习笔记 【C++】
2024-12-09 - 第 38 篇 贪心算法 - 学习笔记 作者(Author): 郑龙浩 / 仟濹(CSND账号名) 贪心算法 学习课程: https://www.bilibili.com/video/BV1f84y1i7mv/?spm_id_from333.337.search-card.all.click&vd_source2683707f584c21c57616cc6ce8454e2b 一、基本…...

精确的单向延迟测量:使用普通硬件和软件
论文标题:Precise One-way Delay Measurement with Common Hardware and Software(精确的单向延迟测量:使用普通硬件和软件) 作者信息:Maciej Muehleisen 和 Mazen Abdel Latif,来自Ericsson Research Eri…...

【MySQL 进阶之路】存储引擎和SQL优化技巧分析
1.InnoDB和MyISAM存储引擎的区别是什么?你在哪些场景下选择InnoDB? Innodb是高并发,支持事务跟行级锁,myisam不支持事务和行级锁,支持表级锁,不支持高并发。innodb底层是B树,适合范围查询&#…...

vue+elementUI从B页面回到A页面并且定位到A页面的el-tabs的某个页签
场景 做项目碰到一个需求,不能使用组件缓存keep-alive,但是需要跳转到B页面后,点击B页面的返回回到A页面的某个页签,灵机一动利用路由拦截去判断即将要跳转的页面后,在获取vm里对应的标签变量进行赋值,实现…...

{结对编程/大模型} 实践营项目案例 | 基于RAG搭建政策问答智能聊天助手
在构建政策问答智能聊天助手的过程中,我们采用了 RAG(Retrieval-Augmented Generation)技术。RAG 是一种结合了检索和生成的混合型自然语言处理技术,它通过检索相关信息来增强生成模型的上下文理解能力。RAG 的主要优点在于能够有…...

【Canvas与图标】乡土风金属铝边立方红黄底黑字图像处理图标
【成图】 120*120图标: 大小图: 【代码】 <!DOCTYPE html> <html lang"utf-8"> <meta http-equiv"Content-Type" content"text/html; charsetutf-8"/> <head><title>金属铝边立方红黄底黑…...

【开源】A064—基于JAVA的民族婚纱预定系统的设计与实现
🙊作者简介:在校研究生,拥有计算机专业的研究生开发团队,分享技术代码帮助学生学习,独立完成自己的网站项目。 代码可以查看项目链接获取⬇️,记得注明来意哦~🌹 赠送计算机毕业设计600个选题ex…...

C++实现一个经典计算器(逆波兰算法)附源码
1、本篇要实现的内容 最近,大家讨论计算器的实现比较热,今天我也来用C和Visual Studio实现一个计算器的小程序。这里使用逆波兰算法,能够根据当前用户输入的算式表达式字符串,计算出所要的结果,算式字符串可以包括加、…...