【疯狂造轮子-iOS】JSON转Model系列之二

1. 前言


上一篇《【疯狂造轮子-iOS】JSON转Model系列之一》实现了一个简陋的JSON转Model的库,不过还存在很多问题。下面我会尝试一个个去解决。

2. 存在问题及解决思路


2.1 没有考虑JSON数据并不一定是NSDictionary类型

有时候JSON并不一定是NSDictionary类型,可能是一个字符串,也可能是NSData类型的数据。不过不管是哪种类型,统统先将其转化为NSData数据,然后使用+[NSJSONSerialization JSONObjectWithData:options:error:]来转化。所以我在initWithAttributes:上面又封装了一层。

- (instancetype)initWithJSONData:(id)json
{
    NSDictionary *dict = [self pjx_dictionaryWithJSON:json];
    return [self initWithAttributes:dict];
}
 
/**
 * @brief 将NSString和NSData格式的json数据转化为NSDictionary类型
 */
- (NSDictionary *)pjx_dictionaryWithJSON:(id)json
{
    if (!json) {
        return nil;
    }
    // 若是NSDictionary类型,直接返回
    if ([json isKindOfClass:[NSDictionary class]]) {
        return json;
    }
 
    NSDictionary *dict = nil;
    NSData *jsonData = nil;
 
    if ([json isKindOfClass:[NSString class]]) {
        // 如果是NSString,就先转化为NSData
        jsonData = [(NSString*)json dataUsingEncoding:NSUTF8StringEncoding];
    } else if ([json isKindOfClass:[NSData class]]) {
        jsonData = json;
    }
 
    if (jsonData && [jsonData isKindOfClass:[NSData class]]) {
        // 如果时NSData类型,使用NSJSONSerialization
        NSError *error = nil;
        dict = [NSJSONSerialization JSONObjectWithData:jsonData options: error:&error];
        if (error) {
            NSLog(@"pjx_dictionaryWithJSON error:%@", error);
            return nil;
        }
        if (![dict isKindOfClass:[NSDictionary class]]) {
            return nil;
        }
    }
 
    return dict;
}

为此,我在ViewController添加了两个sample。分别用来解析NSString类型的JSON数据和NSData类型的JSON数据。

// NSString类型的JSON数据
- (void)runSimpleSample2
{
    NSString *userStr = @"                                                              \
                        {                                                               \
                            \"username\"       : \"shuaige\",                           \
                            \"password\"       : \"123456\",                            \
                            \"avatarImageURL\" : \"http://www.example.com/shuaige.png\" \
                        }";
 
    PJXUser *user = [[PJXUser alloc] initWithJSONData:userStr];
 
    NSLog(@"runSimpleSample2\n");
    NSLog(@"----------------------------------------");
    NSLog(@"username:%@\n",user.username);
    NSLog(@"password:%@\n",user.password);
    NSLog(@"avatarImageURL:%@\n",user.avatarImageURL);
}
 
// NSData类型的JSON数据
- (void)runSimpleSample3
{
    NSString *userInfoFilePath = [[NSBundle mainBundle] pathForResource:@"UserInfo" ofType:@"txt"];
    NSData *data = [NSData dataWithContentsOfFile:userInfoFilePath];
    PJXUser *user = [[PJXUser alloc] initWithJSONData:data];
 
    NSLog(@"runSimpleSample3\n");
    NSLog(@"----------------------------------------");
    NSLog(@"username:%@\n",user.username);
    NSLog(@"password:%@\n",user.password);
    NSLog(@"avatarImageURL:%@\n",user.avatarImageURL);
}

输出结果也是正确的:

2.2 没有考虑用户传入的JSON数据的key值和property的名称不一致

我第一反应是使用一个映射表。也就是说用户使用时需要自定义一套property和key的映射表。YYModel中使用了一个+ (NSDictionary *)modelCustomPropertyMapper函数,用户可以自定义该函数达到映射表的效果,而这个函数是放在一个protocol中的。我挺认同这种设计的,因为modelCustomPropertyMapper这种函数和Model是一种组合关系,可有可无(optional),所以设计成协议更合适。但是作者在设计protocol又说了一句:

// There's no need to add '<YYModel>' to your class header.
@protocol YYModel <NSObject>

 

什么意思呢,就是说你自定义一个NSObject子类(如YYBook)时,如果想实现自定义的property映射关系,只需要实现modelCustomPropertyMapper函数即可,而不需要写成@interface YYBook : NSObject <YYModel>。作者的意思是你遵不遵循YYModel这个protocol都没事,反正你只要在YYBook实现了modelCustomP

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

lmr廖

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值