将json数据映射到本地数据模型对象的一点想法

本文探讨了如何利用iOS运行时(runtime)提高效率,将接收到的JSON数据快速映射到本地数据模型对象。通过创建一个基类,并让所有数据模型继承自该基类,可以简化JSON到对象的转换过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在日常的开发中我们经常遇到的一种情况就是把从服务端请求回来的数据(此处暂且就当做是json的数据格式)映射成本地数据模型的对象。如果一个对象一个对象的去初始化,势必很浪费时间,这里是自己总结的一点想法:运用iOS的强大的运行时(runtime)来对这项工作做一个较统一的处理,废话不多说直接上代码。


1、首先声明一个基类PHObject代码如下

PHObject.h

@interface PHObject : NSObject<NSCopying,NSCoding>

// 解析API返回的JSON,返回对应的Model
- (id)initWithDictionary:(NSDictionary *)JSON;

// JSON key到property的映射关系(支持字典嵌套)
- (NSDictionary *)JSONKeysToPropertyKeys;

// JSON key到 array property的映射关系
- (NSDictionary *)JSONKeysToArrayPropertyKeys;

PHObject.m(此处尚未实现NSCopying和NSCoding协议

//https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtPropertyIntrospection.html

#import "PHObject.h"
#import <objc/runtime.h>


@implementation PHObject

// 解析API返回的JSON,返回对应的Model对象
- (id)initWithDictionary:(NSDictionary *)JSON{
    if(self = [super init]){
        [JSON enumerateKeysAndObjectsUsingBlock:^(id JSONKey,id JSONObj ,BOOL *stop){
            NSString* propertyKey = [self JSONKeysToPropertyKeys][JSONKey];
            propertyKey = propertyKey ? propertyKey : JSONKey;
            Class classOfProperty = [self propertyClassFromClass:[self class]
                                                  forPropertyKey:propertyKey];
            if(classOfProperty != NULL){
                id propertyValue = nil;
                if([classOfProperty isSubclassOfClass:[PHObject class]] &&
                   [JSONObj isKindOfClass:[NSDictionary class]]){
                    propertyValue = [[classOfProperty alloc] initWithDictionary:JSONObj];
                }
                else if([classOfProperty isSubclassOfClass:[NSArray class]] &&
                        [JSONObj isKindOfClass:[NSArray class]]){
                    propertyValue = [self arrayWithArray:JSONObj
                                         itemClassString:[self JSONKeysToArrayPropertyKeys][JSONKey]];
                }
                else{
                    propertyValue = JSONObj;
                }
                [self setValue:propertyValue forKey:propertyKey];
            }
        }];
    }
    return self;
}
//输出字符串的格式有待完善优化
- (NSString*)description
{
    NSMutableDictionary* descDict = [[NSMutableDictionary alloc] init];
    unsigned int outCount;
    objc_property_t* propertylist = class_copyPropertyList([self class], &outCount);
    for(int idx = 0; idx < outCount; ++idx){
        objc_property_t property = *(propertylist + idx);
        const char* propertyNameOfChar = property_getName(property);
        if(propertyNameOfChar != NULL){
            NSString* propertyName = [NSString stringWithUTF8String:propertyNameOfChar];
            id propertyValue = [self valueForKey:propertyName];
            [descDict setObject:propertyValue forKey:propertyName];
        }
    }
    return [descDict description];
}

// JSON key到property的映射关系
- (NSDictionary *)JSONKeysToPropertyKeys{
    return nil;
}

// JSON key到 array property的映射关系
- (NSDictionary *)JSONKeysToArrayPropertyKeys
{
    return nil;
}

//NSCopying协议实现
- (id)copyWithZone:(NSZone *)zone{
    id obj = [[[self class] allocWithZone:zone] init];

    return obj;
}

// NSCoding协议实现
- (id)initWithCoder:(NSCoder *)aDecoder{
    if(self = [super init]){
        if(aDecoder){

        }
    }
    return self;
}

- (void)encodeWithCoder:(NSCoder *)aCoder{
    if(aCoder){
        
    }
}

#pragma mark private method
//从类的属性获取对应属性的类
- (Class)propertyClassFromClass:(Class)objClass
                 forPropertyKey:(NSString*)propertyKey
{
    //获取对应key的属性
    objc_property_t property = class_getProperty(objClass, propertyKey.UTF8String);
    //获取对应属性的类型
    const char* propertyTypeOfChar = property_copyAttributeValue(property, "T");
    NSString* propertyType = nil;
    if(propertyTypeOfChar != NULL){
        propertyType = [NSString stringWithUTF8String:propertyTypeOfChar];
        propertyType = [propertyType stringByReplacingOccurrencesOfString:@"@" withString:@""];
        propertyType = [propertyType stringByReplacingOccurrencesOfString:@"\"" withString:@""];
        free((void*)propertyTypeOfChar);
    }
    return NSClassFromString(propertyType);
}

//从json数组提取对应对象的数组
- (NSArray*)arrayWithArray:(NSArray *)array itemClassString:(NSString*)itemClassString
{
    NSMutableArray* resultArray = [[NSMutableArray alloc] init];
    [array enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop){
        id itemObj = nil;
        Class itemClass = NSClassFromString(itemClassString);
        if([obj isKindOfClass:[NSDictionary class]] &&
           [itemClass isSubclassOfClass:[PHObject class]]){
            itemObj = [[itemClass alloc] initWithDictionary:obj];
        }
        else{
            itemObj = obj;
        }
        [resultArray addObject:itemObj];
    }];
    return resultArray;
}

@end

2、第一点就是基类的声明和实现,接下来只需要所有的数据模型都是继承自PHObject,那么我们的json数据映射本地数据模型对象这项工作就会变的轻而易举。下面举一个例子:

PHUser.h

#import "PHObject.h"

@interface PHUser : PHObject
@property (nonatomic, strong) NSString* name;
@property (nonatomic, strong) NSNumber* age;
@property (nonatomic, assign) BOOL sex;

PHUser.m

#import "PHUser.h"

@implementation PHUser
@synthesize name = _name;
@synthesize age = _age;
@synthesize sex = _sex;

- (NSDictionary *)JSONKeysToPropertyKeys{
    return @{@"name":@"name",
             @"age":@"age",
             @"sex":@"sex"};
}

@end

PHReport.h

#import "PHObject.h"

@class PHUser;

@interface PHReport : PHObject
@property (nonatomic, strong) PHUser* author;
@property (nonatomic, strong) NSString* title;
@property (nonatomic, strong) NSString* date;
@property (nonatomic, strong) NSArray* users;

PHReport.m

#import "PHReport.h"

@implementation PHReport
@synthesize author = _author;
@synthesize title = _title;
@synthesize date = _date;
@synthesize users = _users;

- (NSDictionary *)JSONKeysToPropertyKeys{
    return @{@"author":@"author",
             @"title":@"title",
             @"date":@"date",
             @"users":@"users"};
}

- (NSDictionary *)JSONKeysToArrayPropertyKeys
{
    return @{@"users":@"PHUser"};
}

上面声明两个类PHUser和PHReport分别继承自PHObject

下面通过一个json字典来实例化一个PHReport对象

PHReport * obj = [[PHReport alloc] initWithDictionary:@{
                                                            @"author":@{
                                                                    @"name":@"leon",
                                                                    @"age":@25,
                                                                    @"sex":@YES
                                                                    },
                                                            @"users":@[@{@"name":@"leon1",
                                                                            @"age":@22,
                                                                            @"sex":@YES
                                                                            },
                                                                          @{@"name":@"leon1",
                                                                            @"age":@22,
                                                                            @"sex":@YES
                                                                            },
                                                                          @"testCount"],
                                                            @"title":@"标题",
                                                            @"date":@"日期"
                                                            }];
    NSLog(@"\n%@",obj);

结果:



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值