美文网首页IT好文iOS开发深度好文iOS开发
字典和简单数据模型相互转换(通用版)

字典和简单数据模型相互转换(通用版)

作者: 小白进城 | 来源:发表于2017-08-30 16:45 被阅读36次

    在iOS开发过程中,经常遇到将字典数据转换成model的情况,网上也有很多数据类型转换的框架,像JSONModel、MJExtension等,功能强大,有时间拜读拜读源码


    在维护项目过程中,由于历史问题,并没有使用模型转换框架,每个数据模型都需要手动将字典转化为数据模型,每个模型中都产生了大量的相同的代码,就像下面这样:

    模型初始化

    觉得这样做很傻,重复造轮子,就想着优化方案,花了两三个小时,实现了基本的需求,便在这里记录一下


    基本思路:
    在NSObject类中新增初始化方法,将字典转换为模型对象的属性;
    这样势必要得到对象的成员变量,我们可以使用运行时来得到对象的成员变量,使用KVC方式将字典中各个字段赋值给对应的属性;
    针对字典的key不同于成员变量的问题,可以传递一个映射字典来解决


    实现如下:

    步骤一:

    在NSObject中新增初始化方法

    NSObject.h 文件中

    #import <Foundation/Foundation.h>
    
    @interface NSObject (InitData)
    
    /**
     模型初始化
    
     @param ModelDic 模型字典
     @param hintDic 映射字典,如果不需要则nil
     @return 模型对象
     */
    +(instancetype)objectWithModelDic:(NSDictionary*)modelDic hintDic:(NSDictionary*)hintDic;
    
    @end
    

    .m 文件实现部分

    #import "NSObject+InitData.h"
    #import <objc/runtime.h>
    #pragma clang diagnostic ignored "-Wobjc-designated-initializers"
    @implementation NSObject (InitData)
    +(instancetype)objectWithModelDic:(NSDictionary *)modelDic hintDic:(NSDictionary *)hintDic{
        NSObject *instance = [[[self class] alloc] init];
        unsigned int numIvars; // 成员变量个数
        Ivar *vars = class_copyIvarList([self class], &numIvars);
        NSString *key=nil;
        NSString *key_property = nil;  // 属性
        NSString *type = nil;
        for(int i = 0; i < numIvars; i++) {
            Ivar thisIvar = vars[i];
            key = [NSString stringWithUTF8String:ivar_getName(thisIvar)];  // 获取成员变量的名字
            key = [key hasPrefix:@"_"]?[key substringFromIndex:1]:key;   // 如果是属性自动产生的成员变量,去掉头部下划线
            key_property = key;
            
            // 映射字典,转换key
            if (hintDic) {
                key = [hintDic objectForKey:key]?[hintDic objectForKey:key]:key;
            }
    
            id value = [modelDic objectForKey:key];
            
            if (value==nil) {
                type = [NSString stringWithUTF8String:ivar_getTypeEncoding(thisIvar)]; //获取成员变量的数据类型 
                // 列举了常用的基本数据类型,如果有其他的,需要添加
                if ([type isEqualToString:@"B"]||[type isEqualToString:@"d"]||[type isEqualToString:@"i"]|[type isEqualToString:@"I"]||[type isEqualToString:@"f"]||[type isEqualToString:@"q"]) {
                    value = @(0);
                }
            }
            [instance setValue:value forKey:key_property];
        }
        free(vars);
        return instance;
    }
    @end
    

    这样,所有数据模型都可以直接调用这个方法完成字典转模型操作了,而不用在单独为每个模型编写初始化方法

    简单使用:

    新建Person类

    #import <Foundation/Foundation.h>
    #import <UIKit/UIKit.h>
    
    typedef NS_ENUM(NSInteger , Sex) {
        Male,
        Female
    };
    
    @interface Person : NSObject
    
    @property (copy ,nonatomic) NSString *name;
    @property (assign ,nonatomic) Sex sex;
    @property (assign ,nonatomic) int age;
    @property (assign ,nonatomic) CGFloat height;
    @property (assign ,nonatomic) float money;
    @property (copy ,nonatomic) NSDictionary *otherInfo;
    @property (assign ,nonatomic) BOOL isHandsome;
    @property (copy ,nonatomic) NSArray *familyMember;
    
    @end
    

    使用

    // 新建测试模型字典
        NSDictionary *resDic = @{
                                 @"Name":@"LOLITA0164",
                                 @"sex":@(1),
                                 @"currntAge":@(24),
                                 @"height":@"170.0",
    //                             @"money":@"0.112",   // 可以没有对应字段
                                 @"otherInfo":@{@"profession":@"iOS mobile development"},
                                 @"isHandsome":@(YES),
                                 @"familyMember":@[@"father",@"mother",@"brother",@"older sister"],
                                 @"additional":@"我是测试条件"    // 可以多余字段
                                 };
    
    // 映射字典
        NSDictionary *hintDic = @{
                                  @"name":@"Name",
                                  @"age":@"currntAge"
                                  };
        
        Person *p = [Person objectWithModelDic:resDic hintDic:hintDic];
        
        NSLog(@"\n姓名:%@\n性别:%ld\n年龄:%ld\n身高:%.1f\n存款:%.1f元\n其他信息%@\n帅不:%i\n家庭成员:%@",p.name,(long)p.sex,(long)p.age,p.height,p.money,p.otherInfo,p.isHandsome,p.familyMember);
    

    运行结果:

    运行结果

    结论:

    1、只针对简单数据模型(无模型嵌套),完成字典转模型操作

    2、需要更多的测试,后期需要完善

    3、成员变量或属性皆可


    简单数据模型转字典

    .h

    /**`这里写代码片`
     模型转字典
    
     @param hintDic 映射字典,如果不需要则nil
     @return 结果字典
     */
    -(NSDictionary*)changeToDictionaryWithHintDic:(NSDictionary*)hintDic;
    

    .m

    -(NSDictionary *)changeToDictionaryWithHintDic:(NSDictionary *)hintDic{
        NSMutableDictionary *resDic = [NSMutableDictionary dictionary];
        unsigned int numIvars; // 成员变量个数
        Ivar *vars = class_copyIvarList([self class], &numIvars);
        NSString *key=nil;
        for(int i = 0; i < numIvars; i++) {
            Ivar thisIvar = vars[i];
            key = [NSString stringWithUTF8String:ivar_getName(thisIvar)];  // 获取成员变量的名字
            key = [key hasPrefix:@"_"]?[key substringFromIndex:1]:key;   // 如果是属性自动产生的成员变量,去掉头部下划线
            id value = [self valueForKey:key];
            if (value!=nil) {
                // 映射字典,转换key
                if (hintDic) {
                    key = [hintDic objectForKey:key]?[hintDic objectForKey:key]:key;
                }
                [resDic setValue:value forKey:key];
            }
        }
        free(vars);
        return resDic;
    }
    

    使用

    Person类

    @interface Person : NSObject
    {
        @public
        float height;
    }
    
    @property (strong ,nonatomic) NSString *name;
    @property (assign ,nonatomic) NSInteger age;
    
    @end
    
    NSDictionary *dic = @{
                          @"name":@"LOLITA0164",
                          @"age":@(25),
                          @"height":@(170.0)
                          };
    Person *p = [Person objectWithModelDic:dic hintDic:nil];
    // key的映射(结果字典中的key)
    NSDictionary *hintDic = @{
                             @"name":@"realName",
                             @"age":@"currentAge"
                             };
    NSDictionary *resDic = [p changeToDictionaryWithHintDic:hintDic];
    NSLog(@"%@",resDic);
    

    结果:

    结果

    补充

    简单模型转json

    .h

    /**
     模型转josn
    
     @param hintDic 映射字典
     @return 结果json
     */
    -(NSString*)changeToJsonStringWithHintDic:(NSDictionary*)hintDic;
    

    .m

    -(NSString *)changeToJsonStringWithHintDic:(NSDictionary *)hintDic{
        NSDictionary *resDic = [self changeToDictionaryWithHintDic:hintDic];
        NSData *jsonData = [NSJSONSerialization dataWithJSONObject:resDic options:NSJSONWritingPrettyPrinted error:nil];
        if (jsonData) {
            return [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
        }
        return @"";
    }
    

    使用:

    NSDictionary *dic = @{
                          @"name":@"LOLITA0164",
                          @"age":@(25),
                          @"height":@(170.0)
                          };
    Person *p = [Person objectWithModelDic:dic hintDic:nil];
    // key的映射(结果字典中的key)
    NSDictionary *hintDic = @{
                              @"name":@"realName",
                              @"age":@"currentAge"
                              };
    NSString *resString = [p changeToJsonStringWithHintDic:hintDic];
    NSLog(@"--%@",resString);
    

    结果:

    结果

    相关文章

      网友评论

        本文标题:字典和简单数据模型相互转换(通用版)

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