美文网首页
利用Runtime实现字典转模型

利用Runtime实现字典转模型

作者: zhifan_young | 来源:发表于2017-06-17 17:50 被阅读0次

    参考自:http://www.jianshu.com/p/836f07bb468e

    • Runtime 是一种面向对象编程语言的运行环境
    • OC最主要的特点就是在程序运行时,以发送消息的方式调用方法(也就是常说的OC是基于运行时的)

    一句话概括:通过 Runtime 获取 model 的属性列表,然后遍历字典中的 key,如果属性列表中包含这个 key 则通过 KVC 把字典中对应的 value 赋值到 model 的属性。

    字典转模型核心算法思路.png

    为什么要利用 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

    相关文章

      网友评论

          本文标题:利用Runtime实现字典转模型

          本文链接:https://www.haomeiwen.com/subject/luzvqxtx.html