采用运行时进行复合型数据转模型

关于动态赋值已有不少帖子进行了详细的说明,本帖就不再讨论,采用运行时数据转模型是一种比较简单的且复用性强的方法,然而使用时往往遇到因为数据结构复杂导致复合型json无法完全转化的问题。
本帖主要研究了运行时对模型属性的子属性如何做到循环赋值,第一次发帖如有措辞不当还请见谅。

废话不多说,上代码:
比如有时我们遇到了如下复合型需求的model,网上有很多根据json自动生成model的开源工具用起来很方便,这里使用到的是WHC_DataModelFactory;

#import <Foundation/Foundation.h>

@interface books :NSObject
@property (nonatomic , copy) NSString * book_pic_url;
@property (nonatomic , copy) NSString * book_score;
@property (nonatomic , copy) NSString * book_summary;
@property (nonatomic , strong) NSNumber * book_id;
@property (nonatomic , copy) NSString * author_name;
@property (nonatomic , copy) NSString * book_read_url;
@property (nonatomic , copy) NSString * book_name;
@property (nonatomic , strong) NSNumber * is_member_book;

@end

@interface NRmodel :NSObject
@property (nonatomic , strong) NSArray * books;
@property (nonatomic , copy) NSString * H5bookShelf;
@property (nonatomic , copy) NSString * h5Address;

@end

这个模型中明显是模型中有一个数组,数组装的是子属性books;(由于一般json不会出现多层数组紧邻嵌套的情况,所以本文中未对该情况做循环赋值);
一般情况下,我们用到的运行时遍历字典key进行赋值时会导致该数组存放的是仍一个个字典。
怎么才能让数组中放的是地址(对象)而非字典呢,我们首先需要分辨出字典的value,当其为数组时特殊处理,创建以key值为类名的对象,然后遍历数组对数组内

的字典进行第二次运行时赋值操作,代码如下:

+(id)ccObjectFromClass:(Class)theClass dict:(NSDictionary *)dict {
    if (NO == [dict isKindOfClass:[NSDictionary class]]) {
        return nil;
    }
    //初始化对象
    id object = [[theClass alloc] init];
    for (NSString *key in [dict allKeys]) {
        id value = [dict objectForKey:key];
        
        NSString * propertyString = [NSString stringWithFormat:@"%@%@",[[key uppercaseString] substringToIndex:1],[key substringFromIndex:1]];
        
        NSString *propertySetSel = [NSString stringWithFormat:@"set%@:",propertyString];
        SEL setterSEL = NSSelectorFromString(propertySetSel);
        SEL getterSEL = NSSelectorFromString(key);
        //当字典的对应value也是字典时触发本方法的循环给属性的属性赋值
        if ([value isKindOfClass:[NSDictionary class]]&&[object respondsToSelector:getterSEL]) {
            
            Class theClass1 = NSClassFromString(key);
            id  tempProp =[[theClass1 alloc]init];
            tempProp =[NSObject ccObjectFromClass:[theClass1 class] dict:value];
                [object performSelector:setterSEL withObject: tempProp] ;
        }
        //当字典的对应value是数组时遍历数组,对value的每一个子字典进行本方法的循环给属性数组内包含的属性赋值
        else if ([value isKindOfClass:[NSArray class]]&&[object respondsToSelector:getterSEL]){
            NSMutableArray * arr = [NSMutableArray array];
            for (id contain in value) {
                if ([contain isKindOfClass:[NSArray class]]) {
                     [object performSelector:setterSEL withObject:value];
                }else if([contain isKindOfClass:[NSDictionary class]]){
                    Class theClass2 = NSClassFromString(key);
                    id  tempProp =[[theClass2 alloc]init];
                    tempProp =[NSObject ccObjectFromClass:[theClass2 class] dict:contain];
                    NSLog(@"%@",tempProp);
                    [arr addObject:tempProp];
                }
                [object performSelector:setterSEL withObject:arr];
                }
        }
        if ([object respondsToSelector:setterSEL]) {
            const char *propertyName = [key cStringUsingEncoding:NSUTF8StringEncoding];
            objc_property_t properties = class_getProperty(theClass, propertyName);
            if (properties) {
                const char *propertyAtt = property_getAttributes(properties);
                NSString *propertyAttS = [NSString stringWithCString:propertyAtt encoding:NSUTF8StringEncoding];
                if ([propertyAttS rangeOfString:@"NSNumber"].length > 0) {
                    if ([value isKindOfClass:[NSString class]]) {
                        NSNumber *newValue = @([value doubleValue]);
                        value = newValue;
                    }
                }
            }
            if ([value isKindOfClass:[NSString class]]) {
                if (![value isEqualToString:nullString]) {
                    [object performSelector:setterSEL withObject:value];
                }
            }
            else if (![value isEqual:[NSNull null]] && ![value isKindOfClass:[NSArray class]] && ![value isKindOfClass:[NSDictionary class]]) {
                [object performSelector:setterSEL withObject:value];
            }
        }
    }
    return [object autorelease];
}

上述代码,分别对数组和字典相互嵌套,字典与字典嵌套的json进行了额外处理,最终目的是使用model时无需二次赋值,直接获取属性的子属性即可进行操作,比如字典与字典相互嵌套即可用model的点语法获取属性的属性使操作更加便捷。
以上,谢谢
新人发贴,大神们手下留情

    原文作者:墨鱼
    原文地址: https://segmentfault.com/a/1190000004877548
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞