iOS高级理论:Runtime应用

一、遍历类的属性,快速归档

在 iOS 中,可以使用 Runtime 遍历类的属性来实现快速的归档(Archiving)操作。归档是将对象转换为数据流以便存储或传输的过程。下面是一个简单的示例,展示如何使用 Runtime 遍历类的属性进行归档操作:

假设有一个名为 Person 的类,我们想要对其属性进行归档操作:

#import <objc/runtime.h>@interface Person : NSObject <NSCoding>
@property (nonatomic, strong) NSString *name;
@property (nonatomic, assign) NSInteger age;
@end@implementation Person- (void)encodeWithCoder:(NSCoder *)coder {unsigned int count;objc_property_t *properties = class_copyPropertyList([self class], &count);for (int i = 0; i < count; i++) {objc_property_t property = properties[i];NSString *propertyName = [NSString stringWithUTF8String:property_getName(property)];id propertyValue = [self valueForKey:propertyName];[coder encodeObject:propertyValue forKey:propertyName];}free(properties);
}- (instancetype)initWithCoder:(NSCoder *)coder {self = [super init];if (self) {unsigned int count;objc_property_t *properties = class_copyPropertyList([self class], &count);for (int i = 0; i < count; i++) {objc_property_t property = properties[i];NSString *propertyName = [NSString stringWithUTF8String:property_getName(property)];id propertyValue = [coder decodeObjectForKey:propertyName];[self setValue:propertyValue forKey:propertyName];}free(properties);}return self;
}@end

在上面的示例中,encodeWithCoder: 方法遍历了 Person 类的所有属性,并将属性的值使用 NSCoder 进行归桋操作。initWithCoder: 方法则对归档的数据进行解档,恢复对象的状态。

通过使用 Runtime 遍历类的属性,我们可以实现一个通用的归档和解档方法,而无需手动编写大量的归档代码。这样可以提高代码的复用性和可维护性。

二、字典转模型

1、创建一个NSObject的分类

@interface NSObject (Json)
+ (instancetype)dictToModel:(NSDictionary *)dict;
@end

2、实现分类中字典转模型的方法

#import "NSObject+Json.h"
#import <objc/runtime.h>@implementation NSObject (Json)+ (instancetype)dictToModel:(NSDictionary *)dict
{id obj = [[self alloc] init];unsigned int count = 0;Ivar *ivars = class_copyIvarList([self class], &count);for (int i=0; i<count; i++) {Ivar ivar = ivars[i];NSMutableString *name = [NSMutableString stringWithUTF8String:ivar_getName(ivar)];[name deleteCharactersInRange:NSMakeRange(0, 1)];        [obj setValue:dict[name] forKey:name];}return obj;
}
@end

3、调用字典转模型的方法

- (void)viewDidLoad {[super viewDidLoad];NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];[dict setObject:@"张三" forKey:@"name"];[dict setObject:@"20" forKey:@"age"];[dict setObject:@"北京" forKey:@"address"];Student *student = [Student dictToModel:dict];NSLog(@"name:%@\n",student.name);NSLog(@"age:%@\n",student.age);NSLog(@"address:%@\n",student.address);
}

4、运行结果

2019-04-13 10:51:32.136568+0800 AppLife[19195:4640916] name:张三
2019-04-13 10:51:32.136707+0800 AppLife[19195:4640916] age:20
2019-04-13 10:51:32.136803+0800 AppLife[19195:4640916] address:北京

三 防止数组插入空值

1、创建一个NSMutableArray的分类

@interface NSMutableArray (Extension)@end

2、实现分类中方法的交换

#import "NSMutableArray+Extension.h"
#import <objc/runtime.h>@implementation NSMutableArray (Extension)+ (void)load {static dispatch_once_t onceToken;dispatch_once(&onceToken, ^{Class cls = NSClassFromString(@"__NSArrayM");Method method1 = class_getInstanceMethod(cls, @selector(insertObject:atIndex:));Method method2 = class_getInstanceMethod(cls, @selector(cs_insertObject:atIndex:));method_exchangeImplementations(method1, method2);});
}- (void)cs_insertObject:(id)anObject atIndex:(NSUInteger)index {if (anObject == nil) {return;}[self cs_insertObject:anObject atIndex:index];
}@end

3、调用

#import "NSMutableArray+Extension.h"
#import <objc/runtime.h>@implementation NSMutableArray (Extension)+ (void)load {static dispatch_once_t onceToken;dispatch_once(&onceToken, ^{Class cls = NSClassFromString(@"__NSArrayM");Method method1 = class_getInstanceMethod(cls, @selector(insertObject:atIndex:));Method method2 = class_getInstanceMethod(cls, @selector(cs_insertObject:atIndex:));method_exchangeImplementations(method1, method2);});
}- (void)cs_insertObject:(id)anObject atIndex:(NSUInteger)index {if (anObject == nil) {return;}[self cs_insertObject:anObject atIndex:index];
}@end

4、运行结果

2019-04-13 11:24:19.562363+0800 AppLife[20661:4661256] (Test
)

运用Rutime中交换方法的思想,还可以实现拦截所有按钮的点击时间和防止字典中插入空值等。

四、给分类添加属性

1、在分类里声明一个属性

#import "Student.h"@interface Student (Test)
@property (nonatomic, copy) NSString *englishName;
@end

2、实现get和set方法

@implementation Student (Test)- (void)setEnglishName:(NSString *)englishName
{// 第一个参数:给哪个对象添加关联// 第二个参数:关联的key,通过这个key获取// 第三个参数:关联的value// 第四个参数:关联的策略objc_setAssociatedObject(self, @"EnglishName", englishName, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}- (NSString *)englishName
{return objc_getAssociatedObject(self, @"EnglishName");
}@end

五、其他

(1) 实现第一个场景:跟踪程序每个ViewController展示给用户的次数,可以通过Method Swizzling替换ViewDidAppear初始方法。创建一个UIViewController的分类,重写自定义的ViewDidAppear方法,并在其+load方法中实现ViewDidAppear方法的交换。

(2) 开发中常需要在不改变某个类的前提下为其添加一个新的属性,尤其是为系统的类添加新的属性,这个时候就可以利用Runtime的关联对象(Associated Objects)来为分类添加新的属性了。

(3) 实现字典的模型和自动转换,优秀的JSON转模型第三方库JSONModel、YYModel等都利用runtime对属性进行获取,赋值等操作,要比KVC进行模型转换更加强大,更有效率。阅读YYModel的源码可以看出,YY大神对NSObject的内容进行了又一次封装,添加了许多描述内容。其中YYClassInfo是对Class进行了再次封装,而YYClassIvarInfo、YYClassMethodInfo、YYClPropertyInfo分别是对Class的Ivar、Method和property进行了封装和描述。在提取Class的相关信息时都运用了Runtime。

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

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

相关文章

uniapp+express前后端小程序获取头像和昵称和code,openid,小程序授权登陆最新教程

目录 0总体思路0.1前端实现&#xff1a;0.2如何阻拦一些页面必须要登陆才能进去呢&#xff1f;0.3后端实现 1.首页2.个人中心页3.授权登陆页3.1.获取微信头像和微信昵称3.1.1官方教程3.1.2实际实现 3.2.获取头像和昵称之后去获取code小程序授权登陆3.3登陆页的整体代码&#xf…

聊聊spring-cloud-kubernetes-client-loadbalancer

序 本文主要研究一下spring-cloud-kubernetes-client-loadbalancer ServiceInstanceListSupplier org/springframework/cloud/loadbalancer/core/ServiceInstanceListSupplier.java public interface ServiceInstanceListSupplier extends Supplier<Flux<List<Ser…

【Leetcode每日一题】二分查找 - 寻找峰值(难度⭐⭐)(20)

1. 题目解析 Leetcode链接&#xff1a;162. 寻找峰值 这个问题的理解其实相当简单&#xff0c;只需看一下示例&#xff0c;基本就能明白其含义了。 核心在于找到题目中所说的峰值并返回他们的下标即可。 2. 算法原理 分析峰顶及其两旁数据的特点 峰顶数据特点&#xff1a;峰…

windows 11+docker desktop+grafana+influxDB+python写入

下载安装docker desktop 出现WSL相关的错误。WSL是一个linux内核的子系统&#xff0c;docker是基于linux内核的&#xff0c;所以运行docker需要WSL。 以管理员权限打开powershell&#xff0c;查看WSL状态 wsl --status 我遇到的错误是因为我关闭了windows的某些更新 执行上…

Android自定义View实现数字密码锁

最近项目上用到一个密码加锁功能&#xff0c;需要一个数字密码界面&#xff0c;就想着封装成一个View来方便管理和使用。 废话不多说&#xff0c;先上最终效果图&#xff1a; 思路 整体可分为2个部分来实现&#xff0c;1.顶部是4个密码位的填充&#xff1b;2.数字键盘部分。整…

VUE基础知识九 ElementUI项目

ElementUI官网 一 项目 最终完成的效果&#xff1a; 切换上边的不同按钮&#xff0c;下方显示不同的表格数据 在src/components下新建不同业务组件的文件夹 1.1 搭建项目 使用脚手架搭建项目后&#xff0c;引入ElementUI&#xff08;搭建、引入ElementUI步骤在第七节里已…

旧衣服回收小程序开发:企业、创业者收益新模式

近年来&#xff0c;我国旧衣回收行业发展迅速。随着大众对衣物的更新需求增加&#xff0c;闲置衣物便也不断增加&#xff0c;我国的旧衣回收行业的市场规模随之增加。 当下&#xff0c;旧衣回收产业链较为完善&#xff0c;主要以出口为主&#xff0c;回收利润较高。与其他行业…

XXL-JOB面试问题

⭐ 作者简介&#xff1a;码上言 ⭐ 代表教程&#xff1a;Spring Boot vue-element 开发个人博客项目实战教程 ⭐专栏内容&#xff1a;个人博客系统 ⭐我的文档网站&#xff1a;http://xyhwh-nav.cn/ 文章目录 XXL-JOB面试问题1. 什么是XXL-Job2. XXL-Job的核心组件是什么3…

【Pytorch深度学习开发实践学习】Pytorch实现LeNet神经网络(1)

1.model.py import torch.nn as nn import torch.nn.functional as F引入pytorch的两个模块 关于这两个模块的作用&#xff0c;可以参考下面 Pytorch官方文档 torch.nn包含了构成计算图的基本模块 torch,nn.function包括了计算图中的各种主要函数&#xff0c;包括&#…

2.23号qt

4.3 颜色对话框 QColorDialog 该类给用户提供了一个颜色对话框&#xff0c;直接调用该类的一个静态成员函数getColor()即可直接弹出颜色对话框。 [static] QColor //返回值类型 返回的是用户选中的颜色 静态函数 QColorDialog::getColor(//函数名 const QColor …

python Matplotlib Tkinter--pack 框架案例

环境 python:python-3.12.0-amd64 包: matplotlib 3.8.2 pillow 10.1.0 版本一 import matplotlib.pyplot as plt from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2Tk import tkinter as tk import tkinter.messagebox as messagebox…

优思学院|精益生产管理在中国的发展前景

在这个快速变化的世界里&#xff0c;有一个管理理念悄然崛起&#xff0c;它就是精益生产。 这个概念最早由詹姆斯P沃麦克、丹尼尔T琼斯和丹尼尔鲁斯在他们的著作《改变世界的机器》中提出&#xff0c;后来在丰田汽车公司的成功实践中得到了广泛的认可。 这本书不仅风靡全球&a…

Springboot中如何记录好日志

Springboot中如何记录日志 日志体系整体介绍 日志一直在系统中占据这十分重要的地位&#xff0c;他是我们在系统发生故障时用来排查问题的利器&#xff0c;也是我们做操作审计的重要依据。那么如何记录好日志呢&#xff1f;选择什么框架来记录日志&#xff0c;是不是日志打越…

Selenium 自动化遇见 shadow-root 元素怎么处理?

shadow-root是前端的特殊元素节点&#xff0c;其使用了一个叫做shadowDOM的技术做了封装&#xff0c;shadowDOM的作用可以理解为在默认的DOM结构中又嵌套了一个DOM结构&#xff08;和iframe有点类似&#xff0c;只不过iframe内嵌的是HTML&#xff09;&#xff0c;我们遇见shado…

MIPS汇编入门

MIPS汇编入门 寄存器种类指令种类寻址方式立即数寻址寄存器寻址基址寻址相对寻址伪直接寻址 指令总览 寄存器种类 MIPS共有32个通用寄存器在汇编中&#xff0c;寄存器标志由$符号开头寄存器表示共有两种方法 直接使用该寄存器对应编号&#xff0c;例如&#xff1a;$0,$31使用对…

管理心得--如何成为优秀的架构师

关注我&#xff0c;持续分享逻辑思维&管理思维&#xff1b; 可提供大厂面试辅导、及定制化求职/在职/管理/架构辅导&#xff1b; 有意找工作的同学&#xff0c;请参考博主的原创&#xff1a;《面试官心得--面试前应该如何准备》&#xff0c;《面试官心得--面试时如何进行自…

LMDeploy 大模型量化部署

Weight Only量化是一种常见的模型优化技术&#xff0c;特别是在深度学习模型的部署中。这种技术仅对模型的权重进行量化&#xff0c;而不涉及激活&#xff08;即模型中间层的输出&#xff09;。选择采用Weight Only量化的原因主要包括以下几点&#xff1a; 减少模型大小 通过将…

VirtualBox虚拟机安装 Linux 系统

要想学习各种计算机技术&#xff0c;自然离不开Linux系统。并且目前大多数生产系统都是安装在Linux系统上。常用的Linux系统有 Redhat&#xff0c;Centos&#xff0c;OracleLinux 三种。 三者的区别简单说明如下&#xff1a; Red Hat Enterprise Linux (RHEL): RHEL 是由美国…

ICASSP2024 | MLCA-AVSR: 基于多层交叉注意力机制的视听语音识别

视听语音识别&#xff08;Audio-visual speech recognition, AVSR&#xff09;是指结合音频和视频信息对语音进行识别的技术。当前&#xff0c;语音识别&#xff08;ASR&#xff09;系统在准确性在某些场景下已经达到与人类相媲美的水平。然而在复杂声学环境或远场拾音场景&…

Qt应用软件【文件篇】XML文件增删查改

文章目录 1. XML文件简介2. XML文件的主要特点3. XML文件的应用场景4. Qt XML文件相关API汇总5. Qt读取XML文件代码示例6. Qt写入XML文件代码示例7. Qt修改XML文件代码示例8. 字符串转换为XML对象9. XML对象转换为字符串10.替换复杂的xml文件中属性,保持格式不变1. XML文件简介…