Runtime 的一些用法
来源:互联网 发布:金蝶软件数据导出 编辑:程序博客网 时间:2024/05/01 07:18
runtime 就是OC 中经常说的 运行时
这里 简单介绍一下 OC 中用到一些场景
1、字典转模型
2、给分类添加关联对象
3、交换方法
runtime 使用的时候一般建立一个 NSObject 的分类Cotegory 。 当然也可以根据 实际情况创建其他类的Cotegory。在创建的文件里面需要导入
#import <objc/runtime.h>
一、字典转模型。
首先 动态的获取 类 的属性名称 -> 然后使用 KVC 进行赋值.
1、首先获取类的属性名称
.h
/** 获取 属性的名称数组 @return 返回对象的属性名称数组 */+ (NSArray *)cz_objPropertiesAry;.m
const void *kPropertiesKey = "kPropertiesKey";+ (NSArray *)cz_objPropertiesAry{ //获取属性数组的指针数组 unsigned int count = 0; objc_property_t *property = class_copyPropertyList([self class], &count); //创建存放数据的数组 NSMutableArray *array = [NSMutableArray array]; //遍历属性数组 for (unsigned int i = 0; i < count; i++) { // 指针 C语言中数组的名字 为第一个元素的指针 objc_property_t pty = property[i]; //获取属性的名字 类型为C的字符串 const char *cName = property_getName(pty); //把C字符串转化为OC字符串 NSString *name = [NSString stringWithCString:cName encoding:NSUTF8StringEncoding]; //[NSString stringWithUTF8String:cName]; 也可以 //把信息添加到数组里面 [array addObject:name]; } //释放属性数组 free(property); return array.copy;}
unsigned int count =0; //下面为数组
objc_property_t *proList = class_copyPropertyList([selfclass], &count);
注意,这个方法获取的数组最后要用 free(proList); 释放掉
class_copyPropertyList 获取 类的属性的列表
class_copyIvarList 获取类的 成员变量的列表
class_copyMethodList 获取类 的方法的列表
class_copyProtocolList 获取类的代理的列表
参数
1、 要获取的这个类 因为是Cotegory 分类 ,使用 self
2、列表里面元素的个数 unsigned int 无符号的整形
返回值:
所有属性的数组 类型为 objc_property_t 的数组
再遍历类的属性数组 ,因为类型为 objc_property_t 是一个指针,使用property_getName获取这个指针对应属性的名字。
使用property_getName 获取的是一个const char 类型C 语言的字符串 再转化为OC的字符串 。最后添加到存储数据的数组里面。
获取到类的属性名称后,就可以使用KVC 就行赋值了。
//所有字典转模型框架 核心算法+ (instancetype)cz_objcWithDictionary:(NSDictionary *)dict{ //实例化对象 id object = [[self alloc]init]; //获取对象的属性名称数组 //1> 获得 self 的属性列表 NSArray *array = [self cz_objPropertiesAry]; //遍历字典 使用KVC 为数组中的属性赋值 [dict enumerateKeysAndObjectsUsingBlock:^(id _Nonnull key, id _Nonnull obj, BOOL * _Nonnull stop) { //需要先判断数组中是否包含 字典的Key if ([array containsObject:key]) { //赋值 [object setValue:obj forKey:key]; } }]; return object;}
使用:
创建一个Person 类 不实现.m
#import <Foundation/Foundation.h>@interface Person : NSObject@property (nonatomic, copy) NSString *name;@property (nonatomic, assign) NSInteger age;@property (nonatomic, assign) double height;@property (nonatomic, copy) NSString *title;@end
在ViewController 里面
导入
#import "Person.h"
#import "NSObject+Runtime.h"
//获取Persion的属性列表数组 NSArray *properties = [Person cz_objPropertiesAry]; NSLog(@"%@",properties); NSDictionary *dic = @{@"name":@"张三",@"age":@(22),@"height":@(168),@"title":@"运行时",@"place":@"boss"}; Person *persion = [Person cz_objcWithDictionary:dic]; NSLog(@"%@",persion);
二、添加关联 动态的添加属性值
修改获取类属性的方法
const void *kPropertiesKey = "kPropertiesKey";+ (NSArray *)cz_objPropertiesAry{ #pragma mark 关联对象 获取 属性值 没有 则添加属性值 (动态的添加属性值) /* 此方法虽然能够获取类的属性数组 但是如果每次调用都要执行一次的话 耗费的时间长, 使用 关联对象 动态的添加属性值 分别在方法的开头和结尾 */ /* 参数: 1、对象 self 2、const void 的key 返回值 : Id类型 添加的属性值 */ NSArray *proList = objc_getAssociatedObject(self, kPropertiesKey); if (proList) { //如果获取的关联对象里面有元素 就直接返回 return proList; } //获取属性数组的指针数组 unsigned int count = 0; objc_property_t *property = class_copyPropertyList([self class], &count); //创建存放数据的数组 NSMutableArray *array = [NSMutableArray array]; //遍历属性数组 for (unsigned int i = 0; i < count; i++) { // 指针 C语言中数组的名字 为第一个元素的指针 objc_property_t pty = property[i]; //获取属性的名字 类型为C的字符串 const char *cName = property_getName(pty); //把C字符串转化为OC字符串 NSString *name = [NSString stringWithCString:cName encoding:NSUTF8StringEncoding]; //[NSString stringWithUTF8String:cName]; 也可以 //把信息添加到数组里面 [array addObject:name]; } //释放属性数组 free(property); #pragma mark 关联对象 2 添加属性值 动态的添加属性值 /* 参数: 1、对象 self 2、const void 的key 同第一步 3、添加的属性值 4、关联的协议 */ objc_setAssociatedObject(self, kPropertiesKey, array.copy, OBJC_ASSOCIATION_RETAIN_NONATOMIC); return array.copy;}
修改的方法 里面 多了几行代码
NSArray *proList = objc_getAssociatedObject(self, kPropertiesKey); if (proList) { return proList; }
objc_setAssociatedObject(self, kPropertiesKey, array.copy, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
分别在方法的开始和结尾
objc_getAssociatedObject 获取关联对象动态添加的属性值
参数:
1、对象 self
2、const void 的key
返回值:
Id类型, 添加的属性值
objc_setAssociatedObject 设置动态添加关联对象的属性值
参数:
1、对象 self
2、const void 的key 跟上面获取的key一致
3、要添加的属性值,(如果设置了,上面的objc_getAssociatedObject 就能直接获取到,下次调用就能直接获取属性值)
4、关联的协议 OBJC_ASSOCIATION_RETAIN_NONATOMIC添加了 了关联对象 的方法,下次调用该方法的时候,运行到objc_getAssociatedObject 就能直接获取到 数据了,不用再往下执行了。
三、交换方法
特点:
在无法修改系统方法 ,和第三方框架的时候,
1、利用交换方法,先执行自定义的方法
2、再执行系统方法或第三方框架方法。
被称之为 黑魔法 ,对系统和框架有很强的依赖性。
举个例子:
UIImageView *imageView = [[UIImageView alloc]initWithFrame:CGRectMake(0, 0, 200, 200)]; imageView.center = self.view.center; [self.view addSubview:imageView]; imageView.image = [UIImage imageNamed:@"image5.png"];
在UIImageView 的时候,系统的设置图片的方法, imageView.image = [UIImage imageNamed:@""];
imageView.image 相当于 imageView setImage: UIImage
我们可以自定义一个方法,替换掉系统的setImage: 方法
创建一个UIImageView 的Cotegory
//在类 被加载到运行时的时候,就会执行+ (void)load{ //交叉方法 就下面的3句话 //获取 类 实例化的原始方法 setImage: Method originalMethod = class_getInstanceMethod([self class], @selector(setImage:)); //获取 自定义的类的实例化的方法 cz_setImage: Method swizzleMethod = class_getInstanceMethod([self class], @selector(cz_setImage:)); //交换两个方法 setImage: 和 cz_setImage: 完成之后 //1> 调用setImage: 相当于调用 cz_setImage: //2> 调用 cz_setImage: 相当于调用 setImage: method_exchangeImplementations(originalMethod, swizzleMethod);}//自定义 的 类 的实例化方法 Cotegory- (void)cz_setImage:(UIImage *)image{ //这里是我们想要做的事情 NSLog(@"调用的自定义的方法: %s",__FUNCTION__); <span style="white-space:pre"></span> //再调用系统 的默认方法 /*重点 : 为什么 方法名是自定义方法 而不是系统默认的方法名字 是因为load 里面 系统默认方法和自定义的方法进行了交换 系统默认的方法 setImage: 变成了 cz_setImage: 所以 在交换方法完成之后 再次调用系统默认的方法就变成了 我们自定义的方法 */ [self cz_setImage:result];}
首先先自定义一个设置图片的方法- (void) cz_setImage:(UIImage *)image
里面 输出 当前的方法。
在方法 + (void) load{} 里面添加 我们的交换方法
就3句话,
1、获取系统默认的 设置图片的方法
2、获取自定义的设置图片的方法
3、交换这两个方法
class_getInstanceMethod 获取类的实例的方法
参数:
1、类的实例 [self class] (这是一种特殊的实例化对象)
2、获取的实例方法 SEL返回值:
Method 方法 类型
method_exchangeImplementations
参数:
1、要交换的第一个方法
2、要交换的第二个方法
重点注意:
在方法交换之后,两个方法已经被交换了,调用系统方法 变成调用自定义的方法名
调用自定义的方法 变成调用系统的方法名
所以下面:
//自定义 的 类 的实例化方法 Cotegory- (void)cz_setImage:(UIImage *)image{ //这里是我们想要做的事情 输出当前调用的方法 NSLog(@"调用的自定义的方法: %s",__FUNCTION__); <span></span> //再调用系统 的默认方法 /*重点 : 为什么 方法名是自定义方法 而不是系统默认的方法名字 是因为load 里面 系统默认方法和自定义的方法进行了交换 系统默认的方法 setImage: 变成了 cz_setImage: 所以 在交换方法完成之后 再次调用系统默认的方法就变成了 我们自定义的方法 */ 这个时候系统默认的方法名 在这里变成了 <span style="font-family: Arial, Helvetica, sans-serif;">cz_setImage:</span> [self cz_setImage:result];}
ViewController 的运行结果为
#import "UIImageView+RuntimeCrossoverMethod.h"
UIImageView *imageView = [[UIImageView alloc]initWithFrame:CGRectMake(0, 0, 200, 200)]; imageView.center = self.view.center; [self.view addSubview:imageView]; imageView.image = [UIImage imageNamed:@"image5.png"];
2016-10-14 16:38:01.248 Runtime[4947:837294]调用的自定义的方法: -[UIImageView(RuntimeCrossoverMethod) cz_setImage:]
- RunTime的一些用法
- Runtime 的一些用法
- ios的runtime的一些小用法
- runtime的一些理解与用法
- runtime 的一些作用
- Runtime.addShutdownHook的用法
- Runtime类的用法
- Runtime.exec的一些事
- runtime一些有用的东西
- ios runtime的一些知识
- Runtime.getRuntime().exec()的用法
- Runtime.getRuntime.exec()的用法
- runtime用法
- runTime用法
- Objective C Runtime的一些笔记
- 调用Runtime.exec()的一些陷阱
- Java中Runtime.exec的一些事
- Java中Runtime.exec的一些事
- 免费版网络验证系统的全自动发卡功能
- Windows下面安装apache+php+mysql开发环境
- [FAQ19108]如何用MMU增强保护buddy system?
- HTMl5的sessionStorage和localStorage
- JAVA的反射机制
- Runtime 的一些用法
- Dalvik虚拟机为新创建对象分配内存的过程分析
- 求序列中只出现一次的元素
- java并发读&写文件
- Android多媒体播放器源码解析(stagefright框架)
- Java 中Vector、ArrayList和LinkedList 的区别
- Visual Studio 的生成事件 (vs2010,vs2012,vs2013,vs2015)
- 单片机系统上电后没有正常运行,如何进行故障排查?
- cocos2dx怎么在android studio 运行