当前位置: 首页 > article >正文

iOS Runtime与RunLoop的对比和使用

Runtime 机制

核心概念

  1. Objective-C 的动态特性:Objective-C 是一门动态语言,很多工作都是在运行时而非编译时决定的
  2. 消息传递机制:方法调用实际上是发送消息 objc_msgSend(receiver, selector, ...)
  3. 方法决议机制:动态方法解析、消息转发流程

重要数据结构

  • Class:类对象,包含 isa 指针、superclass 指针、方法缓存等
  • objc_object:所有对象的基类
  • Method:方法结构体,包含 SEL 和 IMP
  • Ivar:实例变量结构体
  • Property:属性结构体
  • Protocol:协议结构体

核心功能

  1. 方法交换 (Method Swizzling)
Method originalMethod = class_getInstanceMethod([self class], @selector(viewDidLoad));
Method swizzledMethod = class_getInstanceMethod([self class], @selector(xxx_viewDidLoad));
method_exchangeImplementations(originalMethod, swizzledMethod);
  1. 动态添加方法
class_addMethod([self class], @selector(resolveThisMethodDynamically), (IMP)dynamicMethodIMP, "v@:");
  1. 关联对象 (Associated Objects)
static char associatedKey;
objc_setAssociatedObject(object, &associatedKey, value, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
id value = objc_getAssociatedObject(object, &associatedKey);
  1. 消息转发机制
// 1. 动态方法解析 
+ (BOOL)resolveInstanceMethod:(SEL)sel;
// 2. 备用接收者 
- (id)forwardingTargetForSelector:(SEL)aSelector;
// 3. 完整消息转发 
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector;
- (void)forwardInvocation:(NSInvocation *)anInvocation;

使用案例

  1. 无侵入埋点统计
// 交换 viewDidAppear: 方法实现 
+ (void)load {static dispatch_once_t onceToken;dispatch_once(&onceToken, ^{ [self swizzleMethod:@selector(viewDidAppear:) withMethod:@selector(swizzled_viewDidAppear:)];});
}- (void)swizzled_viewDidAppear:(BOOL)animated {[self swizzled_viewDidAppear:animated];[Tracking logEvent:@"ViewAppear" params:@{@"class": NSStringFromClass([self class])}];
}
  1. 防止数组越界崩溃
+ (void)load {Method originalMethod = class_getInstanceMethod(NSClassFromString(@"__NSArrayI"), @selector(objectAtIndex:));Method swizzledMethod = class_getInstanceMethod([self class], @selector(safeObjectAtIndex:));method_exchangeImplementations(originalMethod, swizzledMethod);
}- (id)safeObjectAtIndex:(NSUInteger)index {if (index < [self count]) {return [self safeObjectAtIndex:index];}NSLog(@"数组越界");return nil;
}

RunLoop 机制

核心概念

  1. 事件循环机制:保持线程持续运行并处理各种事件
  2. 运行模式 (Mode):包含 Source/Timer/Observer
    • NSDefaultRunLoopMode:默认模式
    • UITrackingRunLoopMode:界面跟踪模式
    • NSRunLoopCommonModes:通用模式集合

核心组件

  1. Source:

    • Source0:非基于端口的,处理应用内部事件
    • Source1:基于端口的,处理系统事件
  2. Timer:基于时间的触发器

  3. Observer:观察 RunLoop 状态变化

RunLoop 生命周期

  1. 通知即将进入 RunLoop
  2. 通知即将处理 Timer
  3. 通知即将处理 Source0
  4. 处理 Source0
  5. 如果有 Source1 准备就绪,跳转处理
  6. 通知即将进入休眠
  7. 通知即将被唤醒
  8. 处理唤醒时收到的消息
  9. 通知即将退出 RunLoop

使用案例

  1. 保持线程常驻
+ (NSThread *)networkThread {static NSThread *thread = nil;static dispatch_once_t onceToken;dispatch_once(&onceToken, ^{ thread = [[NSThread alloc] initWithTarget:self selector:@selector(networkThreadEntryPoint:) object:nil];[thread start];});return thread;
}+ (void)networkThreadEntryPoint:(id)__unused object {@autoreleasepool {[[NSThread currentThread] setName:@"com.company.network"];NSRunLoop *runLoop = [NSRunLoop currentRunLoop];[runLoop addPort:[NSMachPort port] forMode:NSDefaultRunLoopMode];[runLoop run];}
}
  1. 性能优化 - 图片加载
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {// ...[self performSelector:@selector(loadImageForCell:)withObject:cell afterDelay:0 inModes:@[NSDefaultRunLoopMode]];// ...
}- (void)loadImageForCell:(UITableViewCell *)cell {// 实际图片加载逻辑 
}
  1. 卡顿监测
- (void)startMonitor {CFRunLoopObserverRef observer = CFRunLoopObserverCreateWithHandler(kCFAllocatorDefault, kCFRunLoopAllActivities, YES, 0, ^(CFRunLoopObserverRef observer, CFRunLoopActivity activity) {switch (activity) {case kCFRunLoopEntry:NSLog(@"即将进入RunLoop");break;case kCFRunLoopBeforeTimers:NSLog(@"即将处理Timer");break;case kCFRunLoopBeforeSources:NSLog(@"即将处理Source");break;case kCFRunLoopBeforeWaiting:NSLog(@"即将进入休眠");break;case kCFRunLoopAfterWaiting:NSLog(@"刚从休眠中唤醒");break;case kCFRunLoopExit:NSLog(@"即将退出RunLoop");break;}});CFRunLoopAddObserver(CFRunLoopGetMain(), observer, kCFRunLoopCommonModes);CFRelease(observer);
}
  1. NSTimer 在滚动时保持运行
NSTimer *timer = [NSTimer timerWithTimeInterval:1.0 target:self selector:@selector(timerAction:) userInfo:nil repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];

Runtime 与 RunLoop 的协同应用

  1. 异步主线程执行检测
- (void)performOnMainThread:(dispatch_block_t)block {if (strcmp(dispatch_queue_get_label(DISPATCH_CURRENT_QUEUE_LABEL), dispatch_queue_get_label(dispatch_get_main_queue())) == 0) {block();} else {// 检查是否在主线程RunLoop中 if ([NSThread isMainThread]) {// 使用RunLoop在当前迭代中执行 CFRunLoopPerformBlock(CFRunLoopGetMain(), kCFRunLoopCommonModes, block);CFRunLoopWakeUp(CFRunLoopGetMain());} else {dispatch_async(dispatch_get_main_queue(), block);}}
}
  1. 方法调用频率限制
- (void)throttledPerformSelector:(SEL)selector withObject:(id)object {// 取消之前的调用 [NSObject cancelPreviousPerformRequestsWithTarget:self selector:selector object:object];// 延迟执行,确保在RunLoop的下一个周期处理 [self performSelector:selector withObject:object afterDelay:0.1 inModes:@[NSDefaultRunLoopMode]];
}

注意事项

  1. Runtime 使用注意事项:

    • Method Swizzling 应该在 +load 方法中进行
    • 注意线程安全问题
    • 避免过度使用,影响代码可读性
  2. RunLoop 使用注意事项:

    • 不要随意停止主线程的 RunLoop
    • 注意 RunLoop Mode 的选择
    • 避免在 RunLoop 中执行耗时操作
  3. 性能考虑:

    • Runtime 的反射操作比直接调用方法慢
    • RunLoop 的 Observer 会增加运行开销
    • 频繁的 Mode 切换会影响性能

通过合理使用 Runtime 和 RunLoop,可以实现许多强大的功能,但同时也要注意它们带来的复杂性和潜在问题。

相关文章:

iOS Runtime与RunLoop的对比和使用

Runtime 机制 核心概念 Objective-C 的动态特性&#xff1a;Objective-C 是一门动态语言&#xff0c;很多工作都是在运行时而非编译时决定的消息传递机制&#xff1a;方法调用实际上是发送消息 objc_msgSend(receiver, selector, ...)方法决议机制&#xff1a;动态方法解析、…...

解决vscode在任务栏显示白色图标

长久不用&#xff0c;不知道怎么着就显示成白色图标&#xff0c;虽然不影响使用&#xff0c;但是看起来不爽 问了豆包&#xff0c;给了个解决方法&#xff1a; 1、打开隐藏文件&#xff0c; 由于图标缓存文件是隐藏文件&#xff0c;首先点击资源管理器中的 “查看” 菜单&am…...

架构思维:构建高并发扣减服务_分布式无主架构

文章目录 Pre无主架构的任务简单实现分布式无主架构 设计和实现扣减中的返还什么是扣减的返还返还实现原则原则一&#xff1a;扣减完成才能返还原则二&#xff1a;一次扣减可以多次返还原则三&#xff1a;返还的总数量要小于等于原始扣减的数量原则四&#xff1a;返还要保证幂等…...

Vue 3 官方 Hooks 的用法与实现原理

Vue 3 引入了 Composition API&#xff0c;使得生命周期钩子&#xff08;hooks&#xff09;在函数式风格中更清晰地表达。本篇文章将从官方 hooks 的使用、实现原理以及自定义 hooks 的结构化思路出发&#xff0c;全面理解 Vue 3 的 hooks 系统。 &#x1f4d8; 1. Vue 3 官方生…...

Vue3 打印表格、Element Plus 打印、前端打印、表格导出打印、打印插件封装、JavaScript 打印、打印预览

🚀 Vue3 高级表格打印工具封装(支持预览、分页、样式美化) 现已更新至npm # npm npm install vue-table-print# yarn yarn add vue-table-print# pnpm pnpm add vue-table-printgithunb地址: https://github.com/zhoulongshao/vue-table-print/blob/main/README.MD关键词…...

湖北理元理律师事务所:专业债务优化如何助力负债者重获生活掌控权

在当前经济环境下&#xff0c;个人债务问题日益凸显。湖北理元理律师事务所通过其专业的债务优化服务&#xff0c;为负债群体提供了一条合法合规的解决路径。本文将客观分析专业债务规划的实际价值&#xff0c;不涉及任何营销内容。 一、债务优化的核心价值 科学评估&#xf…...

RAGFlow知识检索原理解析:混合检索架构与工程实践

一、核心架构设计 RAGFlow构建了四阶段处理流水线,其检索系统采用双路召回+重排序的混合架构: S c o r e f i n a l = α ⋅ B M...

5月22总结

P1024 [NOIP 2001 提高组] 一元三次方程求解 题目描述 有形如&#xff1a;$ a x^3 b x^2 c x d 0 $ 这样的一个一元三次方程。给出该方程中各项的系数&#xff08;$ a,b,c,d $ 均为实数&#xff09;&#xff0c;并约定该方程存在三个不同实根&#xff08;根的范围在 $ -1…...

Java设计模式之桥接模式:从入门到精通

1. 桥接模式概述 1.1 定义与核心思想 桥接模式(Bridge Pattern)是一种结构型设计模式,它将抽象部分与实现部分分离,使它们可以独立变化。这种模式通过提供桥梁结构(Bridge)将抽象和实现解耦。 专业定义:桥接模式将抽象部分与它的实现部分分离,使它们都可以独立地变化…...

uni-app学习笔记九-vue3 v-for指令

v-for 指令基于一个数组来渲染一个列表。v-for 指令的值需要使用 item in items 形式的特殊语法&#xff0c;其中 items 是源数据的数组&#xff0c;而 item 是迭代项的别名&#xff1a; <template><view v-for"(item,index) in 10" :key"index"…...

MAC电脑中右键后复制和拷贝的区别

在Mac电脑中&#xff0c;右键菜单中的“复制”和“拷贝”操作在功能上有所不同&#xff1a; 复制 功能&#xff1a;在选定的位置创建一个与原始文件相同的副本。快捷键&#xff1a;CommandD用于在当前位置快速复制文件&#xff0c;CommandC用于将内容复制到剪贴板。效果&…...

Regmap子系统之六轴传感器驱动-编写icm20607.c驱动

&#xff08;一&#xff09;在驱动中要操作很多芯片相关的寄存器&#xff0c;所以需要先新建一个icm20607.h的头文件&#xff0c;用来定义相关寄存器值。 #ifndef ICM20607_H #define ICM20607_H /*************************************************************** 文件名 : i…...

常见高危端口解析:网络安全中的“危险入口”

目录 1. 经典高危端口列表 2. 典型漏洞案例&#xff1a;445端口与永恒之蓝 攻击原理 防御方案 Linux命令 2. 防护策略建议 三、扩展思考&#xff1a;从端口到攻防体系 结语 1. 经典高危端口列表 端口号 协议/服务 风险场景 21 FTP 明文传输凭据、弱密码爆破、匿名…...

华为2025年校招笔试手撕真题教程(二)

一、题目 大湾区某城市地铁线路非常密集&#xff0c;乘客很难一眼看出选择哪条线路乘坐比较合适&#xff0c;为了解决这个问题&#xff0c;地铁公司希望你开发一个程序帮助乘客挑选合适的乘坐线路&#xff0c;使得乘坐时间最短&#xff0c;地铁公司可以提供的数据是各相邻站点…...

征程 6 J6E/M linear 双int16量化支持替代方案

1.背景简介 当发现使用 plugin 精度 debug 工具定位到是某个 linear 敏感时&#xff0c;示例如下&#xff1a; op_name sensitive_type op_type L1 quant_dty…...

深度学习模块缝合拼接方法套路+即插即用模块分享

前言 在深度学习中&#xff0c;模型的设计往往不是从头开始&#xff0c;而是通过组合不同的模块来构建。这种“模块缝合”技术&#xff0c;就像搭积木一样&#xff0c;把不同的功能模块拼在一起&#xff0c;形成一个强大的模型。今天&#xff0c;我们就来聊聊四种常见的模块缝…...

改写视频生产流程!快手SketchVideo开源:通过线稿精准控制动态分镜的AI视频生成方案

Sketch Video 的核心特点 Sketch Video 通过手绘生成动画的形式&#xff0c;将复杂的信息以简洁、有趣的方式展现出来。其核心特点包括&#xff1a; 超强吸引力 Sketch Video 的手绘风格赋予了视频一种质朴而真实的质感&#xff0c;与常见的精致特效视频形成鲜明对比。这种独…...

Graphics——基于.NET 的 CAD 图形预览技术研究与实现——CAD c#二次开发

一、Graphics 类的本质与作用 Graphics 是 .NET 框架中 System.Drawing 命名空间下的核心类&#xff0c;用于在二维画布&#xff08;如 Bitmap 图像&#xff09;上绘制图形、文本或图像。它相当于 “绘图工具”&#xff0c;提供了一系列方法&#xff08;如 DrawLine、FillElli…...

ElasticSearch 8.x 快速上手并了解核心概念

目录 核心概念概念总结 常见操作索引的常见操作常见的数据类型指定索引库字段类型mapping查看索引库的字段类型最高频使用的数据类型 核心概念 在新版Elasticsearch中&#xff0c;文档document就是一行记录(json)&#xff0c;而这些记录存在于索引库(index)中, 索引名称必须是…...

AI神经网络降噪 vs 传统单/双麦克风降噪的核心优势对比

1. 降噪原理的本质差异 对比维度传统单/双麦克风降噪AI神经网络降噪技术基础基于固定规则的信号处理&#xff08;如谱减法、维纳滤波&#xff09;基于深度学习的动态建模&#xff08;DNN/CNN/Transformer&#xff09;噪声样本依赖预设有限噪声类型训练数据覆盖数十万种真实环境…...

04-Web后端基础(基础知识)

而像HTML、CSS、JS 以及图片、音频、视频等这些资源&#xff0c;我们都称为静态资源。 所谓静态资源&#xff0c;就是指在服务器上存储的不会改变的数据&#xff0c;通常不会根据用户的请求而变化。 那与静态资源对应的还有一类资源&#xff0c;就是动态资源。那所谓动态资源&…...

Spring Cloud生态与技术选型指南:如何构建高可用的微服务系统?

引言&#xff1a;为什么选择Spring Cloud&#xff1f; 作为全球开发者首选的微服务框架&#xff0c;Spring Cloud凭借其开箱即用的组件、与Spring Boot的无缝集成&#xff0c;以及活跃的社区生态&#xff0c;成为企业级微服务架构的基石。但在实际项目中&#xff0c;如何从众多…...

手写简单的tomcat

首先&#xff0c;Tomcat是一个软件&#xff0c;所有的项目都能在Tomcat上加载运行&#xff0c;Tomcat最核心的就是Servlet集合&#xff0c;本身就是HashMap。Tomcat需要支持Servlet&#xff0c;所以有servlet底层的资源&#xff1a;HttpServlet抽象类、HttpRequest和HttpRespon…...

高等数学-积分

一、不定积分 定理&#xff1a;如果函数f(x)在区间I上连续&#xff0c;那么f(x)在区间I上一定有原函数&#xff0c;即一定存在区间I上的可导函数F(x)&#xff0c;使得F(x)f(x) &#xff0c;x∈I 简单地说&#xff1a;连续函数必有原函数。 极限lim*0->x {[∫*0^x sin(t^2)…...

IOS平台Unity3D AOT全局模块结构分析

分析背景 由于IOS平台中不允许执行动态代码&#xff0c;Unity 4.6之前的版本在IOS平台中采用了AOT的处理方式&#xff0c;提前将C#代码静态编译为机器识别的二进制机器码。Unity引擎4.6之前的版本中IOS框架采用了Mono的AOT机制实现静态编译和处理&#xff0c;本文针对全局AOT模…...

Vue 3.0中自定义指令

自定义指令是增强 Vue 组件的重要手段。常见的内置指令有&#xff1a; v-if、v-show、v-model、v-bind、v-on等。 本文将详细讲解如何创建和使用自定义指令&#xff0c;关注以下几个关键点&#xff1a; 1. 指令的钩子函数&#xff1a;类似于生命周期钩子函数。 2. 指令钩子函…...

在 语义分割 和 图像分类 任务中,image、label 和 output 的形状会有所不同。

1. 图像分类 (Image Classification) 图像分类 任务是将整个图像分类为一个类别。通常&#xff0c;output 是对整个图像的类别的预测&#xff0c;而 label 是该图像的真实类别。 1.1 image 的形状 image 是输入图像数据&#xff0c;通常是一个四维张量&#xff1a; 形状&…...

C++面试4-sizeof解析

C++sizeof关键字的深度解析 一、本质认知:编译器的尺度 1. 编译期操作符的基因 int arr[5]; cout << sizeof(arr); // 输出20(假设int为4字节)非运行时特性:在编译阶段完成计算,不会生成任何机器指令表达式不求值:sizeof(++i)不会改变i的值类型感知:对类型名使…...

CyberSecAsia专访CertiK首席安全官:区块链行业亟需“安全优先”开发范式

近日&#xff0c;权威网络安全媒体CyberSecAsia发布了对CertiK首席安全官Wang Tielei博士的专访&#xff0c;双方围绕企业在进军区块链领域时所面临的关键安全风险与防御策略展开深入探讨。 Wang博士在采访中指出&#xff0c;跨链桥攻击、智能合约漏洞以及私钥管理不当&#x…...

uniapp如何设置uni.request可变请求ip地址

文章目录 简介方法一&#xff1a;直接在请求URL中嵌入变量方法二&#xff1a;使用全局变量方法三&#xff1a;使用环境变量方法四&#xff1a;服务端配置方法五&#xff1a;使用配置文件&#xff08;如config.js&#xff09;:总结 简介 在uni-app中&#xff0c;uni.request 用…...