IT好文iOS开发深度好文iOS开发

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

2017-08-30  本文已影响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);

结果:

结果
上一篇 下一篇

猜你喜欢

热点阅读