runtime常见引用场景:一、关联对象;二、动态获取对象属性,比如实现一个简易的字典转模型方法。 三、交叉方法(黑魔法)
这里介绍用runtime动态获取对象属性,实现一个简易的字典转模型方法。
![](https://img.haomeiwen.com/i2285557/73d95f7daf45f84a.png)
问题:
1.如何动态的获取类的属性列表
2.如何优化,如果类的属性列表已经获取,如何避免反复获取。
- 字典转模型时 KVC赋值时不含有某个属性怎么处理?
实现代码
创建NSObject的分类
NSObject+Runtime.h
@interface NSObject (Runtime)
+ (instancetype)rb_objWithDic:(NSDictionary *)dic;
+ (NSArray *)rb_objPropeties;
@end
NSObject+Runtime.m
+ (instancetype)rb_objWithDic:(NSDictionary *)dic {
// 实例化对象
id object = [[self alloc] init];
// 1>获取对象属性数组
NSArray *propertyArr = [self rb_objPropeties];
[dic enumerateKeysAndObjectsUsingBlock:^(id _Nonnull key, id _Nonnull obj, BOOL * _Nonnull stop) {
// 2>判断数组中是否包含对应的key
if ([propertyArr containsObject:key]) {
// 3> kvc设置数值
[object setValue:obj forKey:key];
}
}];
return object;
}
const char *kPropertListKey = "kPropertListKey";
+ (NSArray *)rb_objPropeties {
// ---1.使用`关联对象`动态获取属性 ,如果有值,就直接返回
/**
参数:
1.对象 self
2.动态属性的 key
返回值:
id 类型
这里关联的是一个数组,∴ 用一个数组接收
*/
NSArray *ptyArr = objc_getAssociatedObject(self, kPropertListKey);
if (ptyArr != nil) {
return ptyArr;
}
/**
运行时获取对象那个属性列表
参数:
1.要获取的类
2.类属性的个数指针
返回值:
所有属性的`数组` ,C 数组的名字 就是指向第一个元素地址
C语言中看到retain/create/copy 需要release。最要option+click查看。
*/
unsigned int count = 0;
objc_property_t *proList = class_copyPropertyList([self class], &count);
// 创建数组
NSMutableArray *arrM = [NSMutableArray array];
// 遍历所有属性
for (unsigned int i =0 ; i<count; i++) {
// 1.从数组中取得属性
// OC中调用C的结构体指针,通常不需要 `*`
objc_property_t pty = proList[i];
// 2.从pty中获取属性的名称
const char * cName = property_getName(pty);
// NSLog(@"%s",cName);
NSString *name = [NSString stringWithCString:cName encoding:NSUTF8StringEncoding];
[arrM addObject:name];
}
// 内存:释放属性数组
free(proList);
// -----2 到此为止 属性数组已经获取完毕,使用关联对象动态的添加属性
/**
参数:
1. 对象 self
2. 动态添加的属性的key , 获取值的时候使用 objc_getAssociatedObject
3. 动态添加的属性的 值
4. 关联策略
*/
objc_setAssociatedObject(self, kPropertListKey, arrM.copy, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
return arrM.copy;
}
网友评论