技术控

    今日:42| 主题:49157
收藏本版 (1)
最新软件应用技术尽在掌握

[其他] 利用 Runtime(运行时)讲解字典转模型的核心算法

[复制链接]
安香屿 发表于 5 天前
27 1

立即注册CoLaBug.com会员,免费获得投稿人的专业资料,享用更多功能,玩转个人品牌!

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
       
  • 运行时(runtime)是一种面向对象的编程语言的运行环境
       
  • OC 最主要的特点就是在程序运行时, 以发送消息的方式调用方法
       
  • 运行时时 OC 的核心, OC 就是基于运行时的
      
  上面的话太抽象了, 运行时能干什么? 这才是最关键的, 当我们老是被问到 YYModel 是怎么实现的时候, 一脸懵逼, 其实,在 YYModel 内部就运用了运行时, 来字典转模型,具体的思路是这样的
  

利用 Runtime(运行时)讲解字典转模型的核心算法-1 (运行环境,编程语言,干什么,模型,程序)

  字典转模型的核心算法思路
  以往, 我们字典转模型,总是需要在模型类中定义一个静态方法或者对象方法,来字典转模型, 这样, 我们在不同的模型中, 都必须定义这样一个方法来完成字典转模型, 如果我们写的项目比较大, 模型比较多,这样字典转模型的效率就太低了,耦合性也比较高, 那我们如何做到字典转模型 与 模型类的彻底解耦呢?
  我们可以创建一个 NSObject 的分类, 因为所有的类(NSProxy 除外)都继承自 NSObject, 那我们就可以用任意的类去调 NSObject 的这个分类方法, 子类可以任意调用父类方法嘛
  那么我们如何在这个分类方法中完成字典转模型呢?
  这里就要用到运行时的概念了,
   首先我们在分类中导入      这个框架, 然后进行第一步,获取属性列表   
  [code]const char *kPropertyListKey = "YFPropertyListKey";
+ (NSArray *)yf_objcProperties
{
     /* 获取关联对象 */
    NSArray *ptyList = objc_getAssociatedObject(self, kPropertyListKey);
     /* 如果 ptyList 有值,直接返回 */
    if (ptyList) {
        return ptyList;
    }
     /* 调用运行时方法, 取得类的属性列表 */
    /* 成员变量:
     * 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 outCount = 0;
    /**
     * 参数1: 要获取得类
     * 参数2: 雷属性的个数指针
     * 返回值: 所有属性的数组, C 语言中,数组的名字,就是指向第一个元素的地址
     */
    /* retain, creat, copy 需要release */
    objc_property_t *propertyList = class_copyPropertyList([self class], &outCount);
    NSMutableArray *mtArray = [NSMutableArray array];
     /* 遍历所有属性 */
    for (unsigned int i = 0; i < outCount; i++) {
         /* 从数组中取得属性 */
        objc_property_t property = propertyList;
         /* 从 property 中获得属性名称 */
        const char *propertyName_C = property_getName(property);
         /* 将 C 字符串转化成 OC 字符串 */
        NSString *propertyName_OC = [NSString stringWithCString:propertyName_C encoding:NSUTF8StringEncoding];
        [mtArray addObject:propertyName_OC];
    }
     /* 设置关联对象 */
    /**
     *  参数1 : 对象self
     *  参数2 : 动态添加属性的 key
     *  参数3 : 动态添加属性值
     *  参数4 : 对象的引用关系
     */
    objc_setAssociatedObject(self, kPropertyListKey, mtArray.copy, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    /* 释放 */
    free(propertyList);
    return mtArray.copy;
}[/code]  其实上面这一长串代码中,只有4句是最关键的
  [code]1./* 获取关联对象 */
    NSArray *ptyList = objc_getAssociatedObject(self, kPropertyListKey);[/code]  如果在程序运行的时候, 模型对象的属性是不会发生变化的, 我们在利用这个函数如果能获取到关联对象的属性列表, 就不用再走下面的代码去利用运行时再去获取属性列表了
  [code]2.objc_property_t *propertyList = class_copyPropertyList([self class], &outCount);[/code]  这句代码就是真正的利用运行时获取属性列表, 这个属性列表是 C 的结构体指针数组,我们必须将其遍历,并利用另外一个函数将取出结构体指针所指向的结构体中国的 C 字符串,也就是属性名称
  [code]3.const char *propertyName_C = property_getName(property);[/code]  获得C字符串后,我们只需要将其转换为 OC 字符串,加到可变数组中即可
  [code]4.objc_setAssociatedObject(self, kPropertyListKey, mtArray.copy, OBJC_ASSOCIATION_RETAIN_NONATOMIC);[/code]  设置属性列表, 就是把已经生成好的属性列表设置到一个类似于属性的东西储存起来, 下次 get 的时候,直接拿出来用即可,有点类似于懒加载.
  获取属性列表之后, 我们就要进行字典转模型的操作了
  首先我们要遍历参数字典, 如果我们获取得属性列表中包含了字典中的 key,就利用 KVC 方法赋值,然后就完成了字典转模型的操作
  [code]+ (instancetype)yf_objcWithDict:(NSDictionary *)dict
{
     /* 实例化对象 */
    id objc = [[self alloc]init];
     /* 使用字典,设置对象信息 */
     /* 1. 获得 self 的属性列表 */
    NSArray *propertyList = [self  yf_objcProperties];
     /* 2. 遍历字典 */
    [dict enumerateKeysAndObjectsUsingBlock:^(id  _Nonnull key, id  _Nonnull obj, BOOL * _Nonnull stop) {
         /* 3. 判断 key 是否字 propertyList 中 */
        if ([propertyList containsObject:key]) {
             /* 说明属性存在,可以使用 KVC 设置数值 */
            [objc setValue:obj forKey:key];
        }
    }];
     /* 返回对象 */
    return objc;
}[/code]  这样, 比如我在 ViewDidLoad 方法中, 自定义一个字典
  然后我只需要一行代码就可以获取到模型对象,如下
  [code]- (void)viewDidLoad {
    [super viewDidLoad];
    /* 创建一个字典 */
    NSDictionary *dict = @{
                           @"name":@"小明",
                           @"age":@18,
                           @"title":@"master",
                           @"height":@1.7,
                           @"something":@"nothing"
                           };
    Person *person = [Person yf_objcWithDict:dict];
}[/code]  而此时, 模型类中,没有添加任何的构造方法,只有单纯的属性,这样就做到了彻底的解耦, 比如我现在再来一个学生(Student)类,我也无需添加构造方法,也同样只需要调用-(instancetype)yf_objcWithDict:dict;即可.
  


利用 Runtime(运行时)讲解字典转模型的核心算法-2 (运行环境,编程语言,干什么,模型,程序)

  模型类只有单纯的属性
  

12下一页
友荐云推荐




上一篇:iOS 中使用 Keychain Services 在应用间共享数据
下一篇:iOS 中的各种锁
酷辣虫提示酷辣虫禁止发表任何与中华人民共和国法律有抵触的内容!所有内容由用户发布,并不代表酷辣虫的观点,酷辣虫无法对用户发布内容真实性提供任何的保证,请自行验证并承担风险与后果。如您有版权、违规等问题,请通过"联系我们"或"违规举报"告知我们处理。

爱妃,别急,洗完澡了我会翻牌子的.
回复 支持 反对

使用道具 举报

*滑动验证:
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

我要投稿

推荐阅读

扫码访问 @iTTTTT瑞翔 的微博
回页顶回复上一篇下一篇回列表手机版
手机版/CoLaBug.com ( 粤ICP备05003221号 | 文网文[2010]257号 )|网站地图 酷辣虫

© 2001-2016 Comsenz Inc. Design: Dean. DiscuzFans.

返回顶部 返回列表