利用Runtime实现字典转模型
参考自:http://www.jianshu.com/p/836f07bb468e
- Runtime 是一种面向对象编程语言的运行环境
- OC最主要的特点就是在程序运行时,以发送消息的方式调用方法(也就是常说的OC是基于运行时的)
字典转模型核心算法思路.png一句话概括:通过 Runtime 获取 model 的属性列表,然后遍历字典中的 key,如果属性列表中包含这个 key 则通过 KVC 把字典中对应的 value 赋值到 model 的属性。
为什么要利用 Runtime 来进行字典转模型:
- 如果是通过在 model 的 .m 中添加字典转模型的方法,那么,当真正在开发项目的时候,由于有各种不同的 model,就需要给每个 model 的 .m 都加上字典转模型的方法。这个方法的思路都是一样的,只是因为 model 中的属性略有变化。
- 所以,我们可以通过为 NSObject 添加一个分类 (因为所有的类(NSProxy 除外)都继承自 NSObjec),利用 Runtime 实现字典转模型的方法,让所有的 model 都可以使用。
首先获取属性列表。
const char *key = "key";
+ (NSArray *)getPropertyArr {
// 获取关联对象
NSArray *proArr = objc_getAssociatedObject(self, key);
if (proArr) return proArr; // 如果有值,直接返回
// 调用运行时方法,获取类的属性列表
/* 成员变量:
* class_copyIvarList(__unsafe_unretained Class cls, unsigned int *outCount)
* 方法:
* class_copyMethodList(__unsafe_unretained Class cls, unsigned int *outCount)
* 属性:
* class_copyPropertyList(__unsafe_unretained Class cls, unsigned int *outCount)
* 协议:
* class_copyProtocolList(__unsafe_unretained Class cls, unsigned int *outCount)
*/
unsigned int count = 0;
// retain, creat, copy 需要release
objc_property_t *property_List = class_copyPropertyList([self class], &count);
NSMutableArray *mtArr = [NSMutableArray array];
// 遍历属性列表, 获取属性名称
for (int i = 0; i < count; i ++) {
objc_property_t pro = property_List[i];
const char *proName_c = property_getName(pro);
NSString *proName = [NSString stringWithCString:proName_c encoding:NSUTF8StringEncoding];
[mtArr addObject:proName];
}
// 设置关联对象
objc_setAssociatedObject(self, key, mtArr, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
free(property_List);
return mtArr;
}
关键步骤:
-
1.
NSArray *proArr = objc_getAssociatedObject(self, key);
如果在程序运行的时候, 模型对象的属性是不会发生变化的, 我们在利用这个函数如果能获取到关联对象的属性列表, 就不用再走下面的代码去利用运行时再去获取属性列表了 -
2.
objc_property_t *property_List = class_copyPropertyList([self class], &count);
这句代码就是真正的利用运行时获取属性列表, 这个属性列表是 C 的结构体指针数组,我们必须将其遍历,并利用另外一个函数将取出结构体指针所指向的结构体中的 C 字符串,也就是属性名称 -
3.
const char *proName_c = property_getName(pro);
获得C字符串后,我们只需要将其转换为 OC 字符串,加到可变数组中即可 -
4.
objc_setAssociatedObject(self, key, mtArr, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
设置属性列表关联, 就是把已经生成好的属性列表通过 key 与当前类关联到一起,需要用的时候通过 key 获取。
获取到属性列表后,进行字典转模型。
+ (instancetype)modelWithDic:(NSDictionary *)dic {
// 实例化当前对象
id objc = [[self alloc] init];
// 获取self 的属性列表
NSArray *proArr = [self getPropertyArr];
// 遍历字典
[dic enumerateKeysAndObjectsUsingBlock:^(id _Nonnull key, id _Nonnull obj, BOOL * _Nonnull stop) {
// 判断 属性列表中是否包含这个 key
if ([proArr containsObject:key]) {
// 如果包含通过 KVC 赋值到 model
[objc setValue:obj forKey:key];
}
}];
return objc;
}
现在就可以定义一个模型,进行字典转模型了
- (void)viewDidLoad {
[super viewDidLoad];
NSDictionary *dic = @{
@"name": @"小李",
@"title": @"司机"
};
Person *personModel = [Person modelWithDic:dic];
NSLog(@"%@ --- %@", personModel.name, personModel.title);
}
转换结果
这就是一些第三方框架,例如 YYModel,MJExtension等的核心算法,希望在用的时候能明白其中的原理。
代码地址:https://github.com/zhifanYoung/json2model-Demo.git