Kingyeung Chan

THINK GREAT THOUGHTS AND YOU WILL BE GREAT

大家好,我系Monster.Chan,一名来自中国的 iOS / AWS / Unity3D 开发者,就职于SAINSTORE。在不断修炼,努力提升自己


结合工作经验,目前写了《Getting Started with AWS》、《Websites & Web Apps on AWS》,欢迎试读或者购买

iOS Mantle使用小记

Mantle简介

Mantlegithub的工程师们弄出来的东西,是iOS和Mac平台下基于Objective-C编写的一个简单高效的模型层框架。

Mantle能做什么

当我们从服务器获取数据,这些数据一般都为JSON格式,我们常用的做法是将JSON数据转为Model对象, 然后我们就从Model对象的属性里读取数据。

也许你已经体会到这时噩梦的开始,因为你每次都要用-initWithDictionarty:(NSDictionary *)dict等类似 方法来初始化,把JSON数据里的值一个一个的赋值给Model对象的属性,是否有一种重复工作的感觉。

当你需要的某个数据在JSON字典数据里层次很深时,需要不断的使用[[obj objectForKey:@"key"] objectAtIndex:index] objectForKey:@""]..., 这么长的代码简直让人崩溃。

这些还没完,如果服务器给你返回的数据并不是你所期望,例如你需要的是NSString,但给你一个NSNumber; 有时你需要NSDate,却给了你NSString。你不得不去做一些判断,写一些转换的代码。还有一种严重的情况, 由于服务器故障,给你返回了一个NSNull,如果你没有做一些判断处理,那么这时你的程序崩溃的几率很大。

Mantle可以轻松把JSON数据、字典Dictionary和模型Objective之间的相互转换,支持自定义映射, 并且内置实现了NSCodingNSCoping,大大简化归档操作。

使用介绍

首先你需要建立一个空工程,把Mantle代码下载回来,拖进你的工程。我还是建议使用CocoaPos 来管理第三方库。大概浏览一下框架目录,如下图:

文件比较多,但我们常用到的就是MTLJSONAdapterMTLModleMTLModel是一个抽象类,它帮我们做了很多工作。 我们要建的Model类应该继承于它,此外你的继承类一定还要实现MTLJSONSerializing协议。MTLJSONAdapter则是 帮我们把JSON数据绑定到Model的属性里,当然,你不用担心会出现NSNull的情况,因为转换后它会自动设置成nil

假设我们需要对象化的数据如下:

NSDictionary *response = @{
                               @"id" : @"1",
                               @"phone" : @"xxxxxxxx",
                               @"date" : @"2016-06-19",
                               @"goldNumber" : @2,
                               @"info":@{@"version":@"1.0"}
                               };

我们新建一个继承MTLModel的类,叫做TestDataModel

#import <Mantle/Mantle.h>

@interface TestDataModel : MTLModel<MTLJSONSerializing>
@property (nonatomic, retain) NSString *memberID;
@property (nonatomic, retain) NSString *mobilePhone;
@property (nonatomic, retain) NSString *createDate;
@property (nonatomic, retain) NSNumber *goldNumber;
@property (nonatomic, retain) NSString *version;
@end

TestDataModel.m文件里,实现MTLJSONSerializing协议里的+ (NSDictionary *)JSONKeyPathsByPropertyKey方法。

@implementation TestDataModel

+ (NSDictionary *)JSONKeyPathsByPropertyKey {

    return @{
             @"memberID" : @"id",//将JSON字典里id键对应的值,赋值给memberID属性
             @"mobilePhone" : @"phone",
             @"createDate" : @"date",
             @"goldNumber" : @"goldNumber",
             @"version": @"info.version"//这个点是什么意思呢,表示将info键对应的子字典里version键对应的值赋给version属性
             };
}

@end

接下来我们将JSON数据和Model的属性进行绑定

TestDataModel *member = [MTLJSONAdapter modelOfClass:[TestDataModel class] fromJSONDictionary:response error:nil];

也许你会有个疑问,如果info键对应的数组,该如何实现呢?

{
    code = 0x0000;
    info =     {
        products =         (
                        {
                imageUrl = "http://www.sainsmart.com/media/imatic/adv/product/default/ad01.png";
                link = "http://www.ebay.com/itm/Raspberry-Pi-3-Model-B-Basic-Starter-Complete-Ultimate-Accessory-Camera-Kit-/301931262954";
                sku = "101-40-179";
            },
                        {
                imageUrl = "http://www.sainsmart.com/media/imatic/adv/product/default/ad04.png";
                link = "http://www.ebay.com/itm/SainSmart-DSO238-2-8-TFT-Digital-Oscilloscope-Kit-DIY-parts-1Msps-Update-DSO138-/301934861076?ssPageName=STRK:MESE:IT";
                sku = "101-10-148";
            },
                        {
                imageUrl = "http://www.sainsmart.com/media/imatic/adv/product/default/ad03.png";
                link = "http://www.sainsmart.com/sainsmart-6-axis-control-palletizing-robot-arm-model-diy-w-arduino-controller-servos-diy.html";
                sku = "20-011-405";
            },
                        {
                imageUrl = "http://www.sainsmart.com/media/imatic/adv/product/default/ad02.png";
                link = "http://www.sainsmart.com/sainsmart-instabots-upright-rover-kit-pro-updated-2-wheel-self-balancing-robot-kit.html";
                sku = "20-014-310";
            }
        );
        version = 0;
    };
    result = 1;
}

假设我们现在需要处理上面的数据,在TestDataModel.h我们新建如下代码:

@interface ProductInfo : MTLModel<MTLJSONSerializing>
@property (nonatomic, retain) NSString *imageUrl;
@property (nonatomic, retain) NSString *link;
@property (nonatomic, retain) NSString *sku;
@end

@interface Product : MTLModel<MTLJSONSerializing>
@property (nonatomic, assign) NSNumber *result;
@property (nonatomic, retain) NSString *code;
@property (nonatomic, retain) NSString *version;
@property (nonatomic, retain) ProductInfo *products;
@end

TestDataModel.m实现+ (NSDictionary *)JSONKeyPathsByPropertyKey, 以及添加+ (NSValueTransformer *)xxxJSONTransformer,xxx就是根据你的属性名来写的。

@implementation Product

+ (NSDictionary *)JSONKeyPathsByPropertyKey {

    return @{@"code":@"code",
             @"result":@"result",
             @"version":@"info.version",
             @"products":@"info.products"};
}

+ (NSValueTransformer *)productsJSONTransformer {

    //return [NSValueTransformer mtl_JSONArrayTransformerWithModelClass:[ProductInfo class]];
    return [MTLJSONAdapter arrayTransformerWithModelClass:[ProductInfo class]];
}

@end

@implementation ProductInfo

+ (NSDictionary *)JSONKeyPathsByPropertyKey {

    return @{@"imageUrl":@"imageUrl",
             @"link":@"link",
             @"sku":@"sku"};
}

@end

一切准备就绪,现在我们来进行绑定

NSError *error;
Product *model = [MTLJSONAdapter modelOfClass:[Product class] fromJSONDictionary:你的数据源变量 error:&error];

NSArray *array = model.products;
for (ProductInfo *info in array) {
    NSLog(@"%@", info.imageUrl);
}
最近的文章

Laravel入门记录

今天有时间打算学习一下Laravel。下面是一些简单的学习记录,希望对各位也有帮助。 基础设置1.安装composer之前就想抽时间学习Laravel,不过觉得安装有点复杂,我想很多人都有过这种想法。这里给大家推荐一个composer的中国镜像,速度真的不错。 安装Composer前确认你已经正确安装了PHP,打开控制台(Mac)执行php -v查看是否输出正确的版本号。 打开控制台并执行以下命令安装最新版的Composer: //下载安装脚本composer-setup.php到...…

继续阅读
更早的文章

Bug_Note

在Coding肯定会遇到各种奇葩的bug,今天就遇上了,适当汇总一些还是有必要的。这章节以后不断增加。 UICollectionViewFlowLayout有点关的the behavior of the UICollectionViewFlowLayout is not defined because:the item height must be less that the height of the UICollectionView minus the section insets ...…

继续阅读