美文网首页
运行时字典转模型,简单到爆炸。

运行时字典转模型,简单到爆炸。

作者: BetterComingDay | 来源:发表于2017-03-23 22:38 被阅读4次

    最近公司后台变动。导致网络框架近乎废弃。需求紧急,情急之下,我只能先完成工作再慢慢优化。
    开始写的字典转模型代码都能恶心到自己。
    eg.

    - (instancetype)initWithDict:(NSDictionary *)dict{
        if (self = [super init]) {
            //方法one
    //        self.price = dict[@"price"];
    //        self.buyNum = dict[@"buyNum"];
    //        self.image = dict[@"image"];
    //        self.name = dict[@"name"];
            //方法two
    //        for (id key in dict) {
    //            [self setValue:dict[key] forKey:key];
    //        }
            //方法three
            [self setValuesForKeysWithDictionary:dict];
        }
        return self;
    }
    
    - (void)setValue:(id)value forUndefinedKey:(NSString *)key{
        NSLog(@"没有找到key:%@",key);
    }
    
    + (instancetype)productInfoWithDict:(NSDictionary *)dict{
        return [[self alloc] initWithDict:dict];
    }
    

    虽然说用了kvc,但是这样的代码确实恶心。于是回忆了一下。用运行时改造了下代码。至少能安慰了自己。

    + (instancetype)productInfoWithDict:(NSDictionary *)dict{
    //    return [[self alloc] initWithDict:dict];
        id object = [[self alloc] init];
        unsigned int count = 0;
        //获取成员属性列表
        Ivar *ivarList = class_copyIvarList(self, &count);
        for (int i=0; i<count; i++) {
            //获取成员属性
            Ivar ivar = ivarList[i];
            //获取成员名
            NSString *propertyName = [NSString stringWithUTF8String:ivar_getName(ivar)];
            //获取成员属性
            //NSString *propertyType = [NSString stringWithUTF8String:ivar_getTypeEncoding(ivar)];
            //获取key 从1开始是为了 干掉_
            NSString *key = [propertyName substringFromIndex:1];
            //这里可以写方法,来区分本地跟后台不一样的字段名即可
            //例如:model取名字为productPrice。后台字段返回为product_price
            //if([key isEqualToString:@"productPrice"]){
            //    key = @"product_price";
            //}
            id value = dict[key];
            if (value) {
                [object setValue:value forKey:key];
            }
        }
        return object;
    }
    

    以下是封装的比较全的字典转模型的方法。

    - (void)transformObjFromDic:(NSDictionary *) objDic
    {
        if (objDic.count == 0) {
            return;
        }
        Class theClass = [self class];
        while (theClass != [VCObjTransformSuperModel class]) {
            unsigned int attCount;
            /* retain, creat, copy 需要release */
            objc_property_t *properties = class_copyPropertyList(theClass, &attCount);
            for (int i = 0; i < attCount; i++) {
                objc_property_t property = properties[i];
                const char *attName = property_getName(property);
                NSString *propertyName = [NSString stringWithUTF8String:attName];
                NSString *rePropertyName = [self keyNameReflactToAttributeName:propertyName];
                id value = [objDic objectForKey:rePropertyName];
                //        const char *attType = property_getAttributes(property);
                if (value == nil || [value isKindOfClass:[NSNull class]]) {
                    continue;
                }else if ([value isKindOfClass:[NSDictionary class]]){
                    Class attClass = [self classReflactToAttributeName:propertyName];
                    if ([attClass conformsToProtocol:@protocol(VCObjTransformProtocol)]) {
                        id<VCObjTransformProtocol> attObj = [[[attClass class] alloc] init];
                        [attObj transformObjFromDic:value];
                        [self setValue:attObj forKey:propertyName];
                    }else{
                        if (attClass) {
                            [self setValue:value forKey:propertyName];
                        }
                    }
                }else if ([value isKindOfClass:[NSArray class]]){//数组
                    NSArray *valueArray = (NSArray *)value;
                    if (valueArray.count == 0) {//数组为空返回
                        continue;
                    }
                    NSMutableArray *attObjArray = [NSMutableArray array];
                    Class attClass = [self classReflactToAttributeName:propertyName];
                    if ([attClass conformsToProtocol:@protocol(VCObjTransformProtocol)]) {//是否是遵守协议的对象
                        for (id valueObj in value) {
                            id<VCObjTransformProtocol> attObj = [[[attClass class] alloc] init];
                            [attObj transformObjFromDic:valueObj];
                            [attObjArray addObject:attObj];
                        }
                    }else{
                        for (id valueObj in value) {
                            if ([valueObj isKindOfClass:[NSDictionary class]]) {
                                [attObjArray addObject:valueObj];
                            }else if ([valueObj isKindOfClass:[NSNumber class]]){
                                [attObjArray addObject:valueObj];
                            }else{
                                [attObjArray addObject:valueObj];
                            }
                        }
                    }
                    [self setValue:attObjArray forKey:propertyName];
                }else if ([value isKindOfClass:[NSNumber class]]){
                    const char *att = property_getAttributes(property);
                    NSString *attType = [NSString stringWithUTF8String:att];
                    NSRange range = [attType rangeOfString:@"NSString"];
                    if(range.location != NSNotFound){
                        NSNumber *newValueNum = (NSNumber *) value;
                        [self setValue:[newValueNum stringValue] forKey:propertyName];
                    }else{
                        [self setValue:value forKey:propertyName];
                    }
                }else{
                    //TODO:hai 最好还能将string转为自定义的基本类型
                    [self setValue:value forKey:propertyName];
                }
            }
            //创建时候计数器+1 这里需要释放。
            free(properties);
            //获取theClass的父类
            theClass = class_getSuperclass(theClass);
        }
    }
    

    有什么不理解随时沟通。

    相关文章

      网友评论

          本文标题:运行时字典转模型,简单到爆炸。

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