美文网首页ios实用开发技巧小知识点
初识Runtime: 简易json 解析封装 model

初识Runtime: 简易json 解析封装 model

作者: 小青蛙的花 | 来源:发表于2017-11-28 18:08 被阅读12次

Runtime是什么

Runtime是什么?其概念无非就是“因为 Objective-C 是一门动态语言,所以它需要一个运行时系统……Runtime 在实际开发中,其实就是一组C语言的函数,当然理解其运行机制对我们写出高质量的代码肯定有帮助,但是对于新手而言,概念听多了总是容易头晕。
所以新手只要知道 Runtime其实就是一组C语言的函数就可以了,但是想提高还是得啃掉这块骨头。

例如 OC的调用具体 C是怎么实现的:

[target doSomething] 会被转化成 objc_msgSend(target, @selector(doSomething));

还是前面的概念“Objective-C 是一门动态语言......”,相信大家刚接触OC的时候肯定肯定看过下面这个例子:

NSData * data = [NSData data]; NSString * str = data;

这段代码在编译的时候不会报错,只有在运行的时候才会报错,这就引出了我们今天的主题,利用 Runtime拿到实例变量,并赋值

实现具体功能

1. 在 OC中拿到类的实例变量核心代码
/* 获取对象的实例变量 */
- (NSArray *)getAllProperties{
    u_int count;
    Ivar *ivarList = class_copyIvarList([self class], &count);
    NSMutableArray *propertiesArray = [NSMutableArray arrayWithCapacity:count];
    for (int i = 0; i < count ; i++){
        const char * ivarName = ivar_getName(ivarList[i]);
        NSString * ivarStr = [NSString stringWithUTF8String: ivarName];
        NSString * ivarType = [NSString stringWithUTF8String:ivar_getTypeEncoding(ivarList[i])];
        NSLog(@"%@",ivarType);
        [propertiesArray addObject:ivarStr];
        NSString * ivarKey = [ivarStr stringByReplacingOccurrencesOfString:@"_" withString:@""];
        /* 属性赋值 */
        [self PropertySetValue:ivarList[i] fotKey:ivarKey withType:ivarType];
    }
    free(ivarList);
    self.propertiesArray = propertiesArray;
    return propertiesArray;
}

这里也可以获取下面四个相关属性
相关属性:

// 描述类中的一个方法
typedef struct objc_method *Method;

// 实例变量
typedef struct objc_ivar *Ivar;

// 类别Category
typedef struct objc_category *Category;

// 类中声明的属性
typedef struct objc_property *objc_property_t;
2.属性赋值

其实只需要赋值的话,代码很少
拿到实例变量:

u_int count;
Ivar *ivarList = class_copyIvarList([self class], &count);

赋值:

object_setIvar(id _Nullable obj, Ivar _Nonnull ivar, id _Nullable value) 
  1. obj 需要赋值的类
  2. ivar 需要赋值的实例变量
  3. value 给变量赋的值
OC中实现赋值核心代码
/* 属性赋值 */
- (void)PropertySetValue:(Ivar)ivar fotKey:(NSString*)key withType:(NSString*)type{
    //获取 value 类型
    DBModelValueType tpye = [DBModelType getModelType:type with:self.dataDic[key]];
        /* 1. 嵌套赋值 属性赋值 */
    if (tpye == DBModelValueType_selfClass) {
        NSString * classStr = [type removeSymbol];
        Class modelClass = NSClassFromString(classStr);
        DBBaseModel * obj = [[modelClass alloc]initModel:self.dataDic[key]];
        object_setIvar(self, ivar, obj);
    }
        /* 2. 数组赋值 属性赋值 */
    if (tpye == DBModelValueType_NSArray) {
        NSString * classStr = [type removeSymbol];
        
        if ([classStr containsString:@"<"]) {
            Class modelClass = NSClassFromString([classStr subStringFrom:@"<" to:@">"]);
            NSMutableArray * modelArray = [NSMutableArray array];
            NSArray * dataArrat  = [NSArray arrayWithArray:self.dataDic[key]];
            for (NSDictionary * dic in dataArrat) {
                DBBaseModel * model = [[modelClass alloc]initModel:dic];
                [modelArray addObject:model];
            }
            object_setIvar(self, ivar, modelArray);
        }
    }
    
              /* 判断是否有多层级解析 */
    if (![[self.HierarchyDic allKeys]containsObject:key] ) {
        /* 3. 单层级 属性赋值 */
        [DBModelConfig modelSetValue:self.dataDic[key] withClass:self withType:tpye withIvar:ivar];
    }
    else{
        /* 4. 多层级 属性赋值 */
        [DBModelConfig modelSetValue:self.dataDic withClass:self withType:tpye withIvar:ivar withHierarchyDic:self.HierarchyDic];
    }
}

赋值的关键是需要判断变量的数据类型,这里需要特殊处理的是 NSDictionary , NSArray还有多层级的解析

测试数据结构如下:

NSDictionary * dic = @{@"sun":@"123",
                           @"dic":@{@"moon":@{@"hour":@"10:12"}},
                           @"price":@{@"rental":@{@"dayPrice":@"199"}},
                           @"list":@[@{@"key":@"1"},
                                     @{@"key":@"2"},
                                     @{@"key":@"3"}],
                           };

DBCarModel * model = [[DBCarModel alloc]initModel:dic];
    NSLog(@"%@  %@ %@",model.sun,model.dayPrice,model.dic.hour);

打印的结果
2017-11-28 17:15:46.344759+0800 GMMC[81507:4313949] 123    199 10:12
  1. 多层级解析
模仿 JSONModel 在.m 里边添加获取层级关系函数
/* 获取层级关系字典 */
- (NSDictionary*)setValueWithHierarchy{
    NSDictionary * dic = @{
                           @"dayPrice":@"price.rental.dayPrice"
                           };
    return dic;
}
  1. 多层级 属性赋值
    多层级需要拿到前面的层级关系HierarchyDic,来逐步解析数据
+ (void)modelSetValue:(id)value withClass:(id)class withType:(DBModelValueType)type withIvar:(Ivar)ivar withHierarchyDic:(NSDictionary*)HierarchyDic{
  
    const char * ivarName = ivar_getName(ivar);
    NSString * ivarStr = [NSString stringWithUTF8String: ivarName];
    NSString * ivarKey = [ivarStr stringByReplacingOccurrencesOfString:@"_" withString:@""];
    NSString * ivarType = [NSString stringWithUTF8String:ivar_getTypeEncoding(ivar)];
    NSArray * keyArray;

    if ([[HierarchyDic allKeys]containsObject:ivarKey]) {
        keyArray = [HierarchyDic[ivarKey] componentsSeparatedByString:@"."];
    }
    NSDictionary * newDic =[NSDictionary dictionaryWithDictionary:value];
    NSString * newValue;
    if (keyArray.count > 0) {
        for (int i = 0; i < keyArray.count; i ++) {
            newDic = newDic[keyArray[i]];
            if (i == keyArray.count - 2) {
                newValue = newDic[keyArray[i+1]];
                break;
            }
        }
    }
    BOOL res_1 = [class isKindOfClass:[NSObject class]];
    if (res_1) {
        object_setIvar(class, ivar, newValue);
    }
}

总结

这篇只是自己在学习时的一些记录,暂时就叫笔记吧。里边还有一些问题没有解决,看了也只会最基本的修改变量的值,具体用法还是需要自己去摸索学习。

大神请看这边

代码的健壮性稍后再说,这个例子里边还有一个问题就是 NSArray 类型的赋值会有问题最后还是源数据的字典。等找到问题解决方法在更新吧

相关文章

网友评论

    本文标题:初识Runtime: 简易json 解析封装 model

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