iOS运行时Runtime在OC中的应用场景

news2024/12/30 3:17:13

本篇将会总结Rutime的具体应用实例,结合其动态特性,Runtime在开发中的应用大致分为以下几个方面:

 一、动态方法交换:Method Swizzling

实现动态方法交换(Method Swizzling )是Runtime中最具盛名的应用场景,其原理是:通过Runtime获取到方法实现的地址,进而动态交换两个方法的功能。使用到关键方法如下: 

  

下面的图展示了自定义方法交换的过程:

1, 实例代码如下:在控制器中自定义两个方法methodA和methodB,然后在类的预加载函数+ (void)load中分别获取方法A和方法B,然后调用method_exchangeImplementations交换方法A和B的实现,当我们实际去调用方法A时,打印methodB,说明方法A的IMP指向了方法B的实现,方法B同理

 2,拦截并替换系统方法

Runtime动态方法交换更多的是应用于系统类库和第三方框架的方法替换。在不可见源码的情况下,我们可以借助Rutime交换方法实现,为原有方法添加额外功能,这在实际开发中具有十分重要的意义。

下面将展示一个拦截并替换系统方法的示例:为了实现不同机型上的字体都按照比例适配,我们可以拦截系统UIFont的systemFontOfSize方法,load方法不需要手动调用,iOS会在应用程序启动的时候自动调起load方法,而且执行时间较早,所以在此方法中执行交换操作比较合适。具体操作如下:

注意: 这里有一个坑,注意避坑,自定义方法 adjust_systemFontOfSize里面最后一句不能写 return [UIFont systemFontOfSize:fontSize * scale];否则会造成死循环,原因:定义一个UILabel对象label,设置字体大小,调用label.font =  [UIFont systemFontOfSize:fontSize];然后systemFontOfSize实现的时候会去调用adjust_systemFontOfSize:方法,然后在adjust_systemFontOfSize:方法最后又调用systemFontOfSize:因为systemFontOfSize:指向adjust_systemFontOfSize:的实现,所以又再一次调systemFontOfSize:如此循环调用就成了死循环

 二,类别(Category)添加新属性

我们在开发中常常使用类目Category为一些已有的类扩展功能。虽然继承也能够为已有类增加新的方法,而且相比类目更是具有增加属性的优势,但是继承会造新了类的属性和方法过多的继承父类,最后类越来越庞大,添加不必要的继承关系无疑增加了代码的复杂度。

遗憾的是,OC的类目并不支持直接添加属性,如果我们直接在分类的声明中写入Property属性,那么只能为其生成set与get方法声明,却不能生成成员变量,直接调用这些属性还会造成崩溃。

所以为了实现给分类添加属性,我们还需借助Runtime的关联对象(Associated Objects)特性,它能够帮助我们在运行阶段将任意的属性关联到一个对象上,下面是相关的三个方法:

注意:key与关联属性一一对应,我们必须确保其全局唯一性,一般可以用static关键字定义一个静态字符串作为key,但我们常常使用@selector(methodName)作为key,可以减少key的定义。

现在演示一个代码示例:为UITableView增加一个分类:UITableView+datas,并为其设置关联属性datas(数据源属性),相关代码如下:

使用@selector(methodName)作为key

 

使用static关键字定义一个静态字符作为key 

测试一下

 

 三、获取类的详细信息

1,获取类的属性(只能获取由property声明的属性,包括.m中的,获取的属性名称不带下划线)列表

2,获取类的成员变量(能够获取.h和.m中的所有属性以及大括号中声明的变量,获取的属性名称有下划线(大括号中的除外))列表 

3.获取类的所有方法 

 4.获取当前遵循的所有协议

 可以打印到协议protocolA

注意:C语言中使用Copy操作的方法,要注意释放指针,防止内存泄漏

四、解决同一方法高频率调用的效率问题

五、方法动态解析与消息转发

Runtime能够让我们在运行时动态添加一个未实现的方法,主要有两个应用场景: 场景1:动态添加未实现方法,解决代码中因为方法未找到而崩溃的问题; 场景2:利用懒加载思路,当一个类中的方法非常多且有些方法不常用的时候如果直接写了方法,那么这些方法会直接加载到内存,于是内存就很大了,所以我们使用runtime的动态添加方法就不会出现这个问题,只有在运行时才会添加到内存,可以使用动态解析添加方法。方法动态解析主要用到的方法如下: 

1.动态添加未实现方法

对象在接收到未知的消息时,首先会调用所属类的方法+resolveInstanceMethod:(实例方法)或者+resolveClassMethod:(类方法)。在这个方法中,我们有机会为该未知消息新增一个”处理方法””。不过使用该方法的前提是我们已经实现了该”处理方法”,只需要在运行时通过class_addMethod函数动态添加到类里面就可以了。

2.解决方法无响应崩溃问题

如果在上一步无法处理消息,则Runtime会继续调以下方法:- (id)forwardingTargetForSelector:(SEL)aSelector

如果一个对象实现了这个方法,并返回一个非nil的结果,则这个对象会作为消息的新接收者,且消息会被分发到这个对象。当然这个对象不能是self自身,否则就是出现无限循环。当然,如果我们没有指定相应的对象来处理aSelector,则应该调用父类的实现来返回结果。

使用这个方法通常是在对象内部,可能还有一系列其它对象能处理该消息,我们便可借这些对象来处理消息并返回,这样在对象外部看来,还是由该对象亲自处理了这一消息。如下代码所示:

这一步合适于我们只想将消息转发到另一个能处理该消息的对象上。但这一步无法对消息进行处理,如操作消息的参数和返回值。

执行OC方法其实就是一个发送消息的过程,若方法未实现,我们可以利用方法动态解析与消息转发来避免程序崩溃,也就是找一个方法的备用接收者,这主要涉及下面一个处理未实现消息的过程: 

3.快速消息转发在项目中的使用

自定义容器 view 转发给自己的 subview

在日常开发中, 我们往往会遇到一个场景, 一个同样的自定义 view 用于 cell 中和不用于 cell 中, 这时候我们会自定义一个 view 暴露如下图所示接口, 供外界调用。

传统做法.m文件里面要写一堆的setter和getter方法:

但这里如果使用快速消息转发, 会是代码更加简洁, 我们仅需要在 - (id)forwardingTargetForSelector:(SEL)aSelector 方法中 return 加在自己中的自定义 view 对象即可, 当然这里要配合 @dynamic 关键字使用。因为 @property 关键字会生成对应的 getter 、setter 方法, 这样的话 cell 相当于实现了 getter 、setter 方法, 自然不会走到 - (id)forwardingTargetForSelector:(SEL)aSelector 中。

而 @dynamic 关键字意味着编译器不会帮助我们自动生成 getter 、setter 方法。这样一来, 相当于我们只申明了这些方法而并没有实现这些方法, 当调用时便会遵循消息转发机制的步骤, 从而调用 - (id)forwardingTargetForSelector:(SEL)aSelector

 

 六、动态操作属性

1.动态修改属性变量

现在假设这样一个情况:我们使用第三方框架里的Person类,在特殊需求下想要更改其私有属性name,这样的操作我们就可以使用Runtime可以动态修改对象属性。

基本思路:首先使用Runtime获取Peson对象的所有属性,找到name,然后使用ivar的方法修改其值。具体的代码示例如下:

setIvar()和valueForKey利用了KVC键值观察的原理

2.实现 NSCoding 的自动归档和解档

归档是一种常用的轻量型文件存储方式,但是它有个弊端:在归档过程中,若一个Model有多个属性,我们不得不对每个属性进行处理,非常繁琐,而且一旦增加几个属性,还得在这两个方法里面加代码,一旦忙起来很容易遗漏。 归档操作主要涉及两个方法:encodeObject 和 decodeObjectForKey,原始的归档方法代码如下:

现在,我们可以利用Runtime来改进它们,关键的代码示例如下:

3.实现字典与模型的转换

字典数据转模型的操作在项目开发中很常见,通常我们会选择第三方如YYModel、JsonModel;其实我们也可以自己来实现这一功能,主要的思路有两种:KVC、Runtime,总结字典转化模型过程中需要解决的问题如下:

现在,我们使用Runtime来实现字典转模型的操作,大致的思路是这样: 借助Runtime可以动态获取成员列表的特性,遍历模型中所有属性,然后以获取到的属性名为key,在JSON字典中寻找对应的值value;再将每一个对应Value赋值给模型,就完成了字典转模型的目的。 代码如下:

 

 

 

 

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

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

相关文章

SpringBoot2.0中MVC和WebFlux控制层Controller对比

本篇文章是SpringBoot2.0关于Controller控制层的对比,相信很多开发最好奇的也是这块。那么小编就带着大家一起先来看一下尝尝鲜,本篇文章比较短小精悍,只讲如何使用,至于原理剖析,后面会讲。阅读时间大概3分钟,现在开始! 文章目录一、演示目录结构二、演示启动类定义…

昨天阅读量900多

今日阅读量还不错的样子,也有900多了,

【C语言】函数递归详解

🚀write in front🚀 📝个人主页:认真写博客的夏目浅石. 🎁欢迎各位→点赞👍 收藏⭐️ 留言📝​ 📣系列专栏:鹏哥带我学c带我飞 💬总结:希望你看…

解析davinci快捷键配置文件

davinci resolve 是一款非线性影片剪辑软件,mac 下快捷键配置文件位于: lucaslucasdeMacBook-Pro DaVinci Resolve % pwd /Users/lucas/Library/Preferences/Blackmagic Design/DaVinci Resolve lucaslucasdeMacBook-Pro DaVinci Resolve % ll | grep k…

“滴灌”代替“漫灌”:“全链路增长”的百度联盟解

作者 | 曾响铃 文 | 响铃说 2021年时,在平台上的日均收益才不足1000元,日活不足1万; 一年时间不到,现在矩阵产品在平台的日均收入已经翻了90倍,日活翻了25倍。 这是一家白牌资讯媒体“早闻天下事”加入百度联盟后发…

跬智信息(Kyligence)荣获浦东新区人工智能创新应用大赛一等奖

近日,2022 浦东新区人工智能创新应用大赛圆满闭幕。经过层层筛选和考核,跬智信息(Kyligence)从 113 支团队中脱颖而出,参赛项目“Byzer 面向 DataAI 的低代码开源编程语言”在技术创新性、创意性以及项目的可落地性、可…

spi访问fpga

SPI 外设的三线/四线模式及时钟极性相位可以配置,支持主机/从机、全双工/半双工,传送数据格式可灵活配置,并且有发送空接收满 SPI 错误等中断事件功能配合应用使用,更多功能详见本系列芯片手册的相关章节。 SPI四线模式框图&…

轻松玩转树莓派Pico之五、FreeRTOS体验

树莓派Pico开发板片上主芯片为RP2040单片机,双核 Arm Cortex-M0 处理器,工作主频为133MHz,264K片上SRAM,和2MByteFlash。 这么大的RAM和Flash资源,不跑一下RTOS操作系统实在有些可惜,这次就先体验一下Fre…

基于新型战争策略优化算法的光伏模型优化(Matlab代码实现)

💥💥💥💞💞💞欢迎来到本博客❤️❤️❤️💥💥💥 🎉作者研究:🏅🏅🏅本科计算机专业,研究生电气学硕…

vscode通过插件一键运行 c++单元测试

gtest使用初探 简介: 本文在 ubuntu18.04 上实现了 googletest 的全局安装,并在一个 demo项目中演示了使用 cmake 引入了该库,实现了在命令行中运行 c 单元测试,包括运行单个 TEST 函数。另外通过 vscode 的插件 C TestMate, 实现…

MATLAB应用2——MATLAB串口采集加速度计数据

串口保存数据为txt格式: clc ; %死机的时候,在命令窗口输入return %getcominstrhwinfo (serial) %寻找串口 delete(instrfindall) %这句话必须有 global xx; global nn; global data1; global s; xx0; nn500; data1(1:nn)0; sserial(COM8); set(s,Bau…

什么?用Python实用脚本也能实现快速卡通画人物头像,这不就是妥妥的QQ秀嘛。

前言 今天我们就利用Python脚本实现天气查询应用吧。直接开整~ 思路分析 从大量照片/卡通数据中习得照片到卡通画的映射。 开发工具 python版本: 3.6 相关模块: pytorch 1.4 tensorflow-gpu 1.14 face-alignment dlib 1.数据准备 训练数据包括…

Linux入门—Shell常用命令之打包压缩

本文由【正厚软件】沙老师提供 打包压缩命令 1. gzip 命令 命令功能:压缩或展开文件 命令格式: ogzip [ -acdfhlLnNrtvV19 ] [-S 后缀] [ 文件名 ... ] :压缩文件 ogunzip [ -acfhlLnNrtvV ] [-S 后缀] [ 文件名 ... ] :解压缩文件…

离线安装harbor容器镜像仓库单机版(harbor-v2.3.5)

记录:358 场景:在CentOS 7.9操作系统上,离线部署harbor容器镜像仓库单机版,使用Redis为外部缓存、使用PostgreSQL为外部数据库、使用docker-ce操作容器、使用docker-compose操作harbor容器镜像仓库。 版本: 操作系统…

OpenAI chatGPT火爆出圈,世界悄悄发生着变化

OpenAI chatGPT火爆出圈,世界悄悄发生着变化一、为什么突然火起来了?二、ChatGPT功能实例2.1 [AI聊天](https://chat.openai.com/chat)2.2 [AI写新闻稿](https://chat.openai.com/chat)2.3 [AI写代码](https://chat.openai.com/chat)2.4 [AI写论文](http…

Kubernetes二进制单节点集群部署

Kubernetes二进制单节点集群部署 常见的K8S按照部署方式 ●Mini kube Minikube是一个工具,可以在本地快速运行一个单节点微型K8S,仅用于学习、预览K8S的一些特性使用部署地址: https://kubernetes.io/docs/setup/minikube ●Kubeadmin Kubea…

浅谈Kernel32.dll(Windows平台下必有的动态库文件)

今天听了前辈的黑客攻击的知识分享,里面比较基础的元素就是Kernel32.dll,我对它感兴趣好久了,今天搜集一些资料,有关Kernel32的。 目录 ​编辑 一、Kernel32介绍 二、Kernel32内存管理 三、引起Kernel32出错的主要元凶 四、解…

【求助帖】从技术转为项目经理后,如何快速进入角色?

近日,看到了一个求助贴,小李今年26岁,干了两年技术后,现在转行到项目经理的岗位。每天东奔西跑、天天加班还是感觉很吃力、工作也没有成效,想问下如何能快速进入角色? 那么小李的一天具体是怎么样的呢&…

追格小程序重磅升级 新亮点来袭!

追格小程序是一个积木式小程序搭建框架,基于UniappWordPress开发,代码免费开源不加密且支持二开,安装追格相应扩展模块,简单配置即可快速搭建不限于圈子社区、知识付费、活动报名、资讯等类型小程序。 新的亮点是什么 追格小程序…

以太网 VLAN(VLAN数据帧格式、交换机接口类型)

2.8.2 以太网 VLAN(VLAN数据帧格式、交换机接口类型) 原始的以太网数据帧没有802.1QTag字段,在网络中进行转发的时候能够被主机接收、解封查看。 而一但有了802.1Q Tag字段的以太网数据帧,主机即使能接收数据帧,也无法…