runtime字典转模型

runtime字典转模型

  • 遍历模型中所有的成员变量ivar
  • 再到字典中去找,用KVC给模型赋值
  • 字典中的Dictionary,二级转换成模型
  • 字典中有Array,根据方法返回的类型,转换成模型
@interface NSObject (Model)
/**
 *  实现二级字典转模型
 */
+ (instancetype)modelWithDict:(NSDictionary *)dict;
/**
 *  数组中的模型
 */
+ (NSDictionary *)objectClassInArray;
@end

#import 
@implementation NSObject (Model)

+ (instancetype)modelWithDict:(NSDictionary *)dict
{
    // 创建对应的类对象
    id objc = [[self alloc] init];
    
    unsigned int count = 0;
    Ivar *ivarList = class_copyIvarList([self class], &count);
    
    for (NSInteger i = 0; i < count; i++) {
        Ivar ivar = ivarList[i];
        
        // 获取成员名
        NSString *propertyName = [NSString stringWithUTF8String:ivar_getName(ivar)];
        
        // 成员属性类型
        NSString *propertyType = [NSString stringWithUTF8String:ivar_getTypeEncoding(ivar)];
        // _source --- @"NSString"
//        NSLog(@"1---%@ --- %@", propertyName, propertyType);
        // 获取key到字典里找: _source->source
        NSString *key = [propertyName substringFromIndex:1];
        
        id value = dict[key];
        
        // 1.二级转换,字典里的字典模型
        // 值是字典,成员变量的类型不是字典,才需要转化
        if ([value isKindOfClass:[NSDictionary class]] && ![propertyType containsString:@"NS"]) {
            
            // \" 看做一个字符,转义字符
            // 字符串截取   @"@\"User\""== @\"User\" ->  User\"            // 去掉两边的引用号 \"
            NSRange range = [propertyType rangeOfString:@"\""];
            // 截取双引号 后面的东西
            propertyType = [propertyType substringFromIndex:range.location + range.length];
            // User\" -> User
            range = [propertyType rangeOfString:@"\""];
            propertyType = [propertyType substringToIndex:range.location];
            
            // 获取到转换的类
            Class modelClass = NSClassFromString(propertyType);
            if (modelClass) {
                // 递归
                value = [modelClass modelWithDict:value];
            }
        }

        // 2.字典里的数组
        if ([value isKindOfClass:[NSArray class]]) { // [propertyType isEqualToString:@"@\"NSArray\""]
            if ([self respondsToSelector:@selector(objectClassInArray)]) {
                NSString *type = [self objectClassInArray][key];
                
                Class modelClass = NSClassFromString(type);
                NSMutableArray *modelArray = [NSMutableArray array];
                
                for (NSDictionary *dict in value) {
                    id model = [modelClass modelWithDict:dict];
                    [modelArray addObject:model];
                }
                value = modelArray;
            }
        }
//        NSLog(@"2---%@ --- %@", propertyName, propertyType);
        
        if (value) {
            // KVC赋值:不能传空的,字典中没有值,就不管了
            [objc setValue:value forKey:key];
        }
    }
    // 释放
    free(ivarList);
    return objc;
}
@end

举个例子

  • MGStudent模型
@interface MGStudent : NSObject
/** 名字 */
@property (nonatomic, copy) NSString *name;
/** 年龄 */
@property (nonatomic, assign) NSInteger age;
/** 有一本书 */
@property (nonatomic, strong) MGBook *book;
/** 拥有的书本 */
@property (nonatomic, strong) NSArray *books;
@end

@implementation MGStudent
+ (NSDictionary *)objectClassInArray
{
    return @{ @"books" : @"MGBook" };
}
@end
  • MGBook模型
@interface MGBook : NSObject
/** 书名 */
@property (nonatomic, copy) NSString *bookName;
/** 出版社 */
@property (nonatomic, copy) NSString *publisher;
/** 价格 */
@property (nonatomic, assign) double price;
@end

执行结果:

runtime字典转模型_第1张图片
字典数据
runtime字典转模型_第2张图片
字典转模型

你可能感兴趣的:(runtime字典转模型)