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

2017-03-23  本文已影响4人  BetterComingDay

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

有什么不理解随时沟通。

上一篇下一篇

猜你喜欢

热点阅读