Mantle

Mantle是什么?

GitHub上的介绍是:

Model framework for Cocoa and Cocoa Touch

这是一个模型框架。那么具体有什么作用?

回忆一下,在开发过程中有没有经常和后台人员沟通关于模型字段命名的问题,是后台人员遵守你的规则,还是你遵守他的规则,或者说各自用不同的。因为这涉及到序列化和反序列化的问题。当然,如果在字段统一的情况下,只需要一句代码就能完成从字典向模型的转换- (void)setValuesForKeysWithDictionary:(NSDictionary *)keyedValues;,但是在实际开发过程中,几乎很难做到这点。比如id在Objective-C中是保留字段。Mantle提供了一个转换方法:根据自定义的属性映射关系进行序列化和反序列化,简单的说就是字段转换。

如何使用?

字段转换

Mantle提供了一个基本类:MTLModel,如果你想使用Mantle的各种功能,那么你所创建的模型必须是这个类的子类。
举个例子,创建一个Member类

Member.h

@interface Member : MTLModel<MTLJSONSerializing>
@property (nonatomic, retain) NSString * memberID;
@property (nonatomic, retain) NSString * mobilePhone;
@property (nonatomic, retain) NSDate * createDate;

Member的父类是MTLModel同时还遵守<MTLJSONSerializing>协议,查看这个协议你会发现里面有个必须实现的方法:

+ (NSDictionary *)JSONKeyPathsByPropertyKey;

这个方法就是前面提到的用于字段转换的,下面实现这个方法

Member.m

+ (NSDictionary *)JSONKeyPathsByPropertyKey{
    return @{@"memberID" : @"id",
             @"mobilePhone" : @"phone",
             @"createDate" : @"date"
             };
}

这里的意思是:客户端这边的memberID字段对应服务端返回的数据中id字段。注意:本地字段在前,服务端字段在后。完成这个方法就代表着当进行序列化或者反序列化的时候,就会根据这个属性映射关系来进行。

最后用一句代码来得到你想要的模型

    NSDictionary *response = @{@"id" : @"1",
                          @"phone" : @"xxxxxxxx",
                          @"date" : @"2014-09-09",
                          };
    Member *member = [MTLJSONAdapter modelOfClass:[Member class] fromJSONDictionary:response error:nil];

当然,Mantle的功能不止上述的一个。介绍其他功能之前,我们先为Member增加几个字段

@interface Member : MTLModel<MTLJSONSerializing>
@property (nonatomic, retain) NSString * memberID;
@property (nonatomic, retain) NSString * mobilePhone;
@property (nonatomic, retain) NSNumber *goldNumber;
@property (nonatomic, retain) NSDate * createDate;
@property (nonatomic, retain) NSURL *url;
@property (nonatomic, assign) NSUInteger age;
@property (nonatomic, assign) BOOL isVip;

拿createDate字段来说,如果想在模型中直接得到NSDate类,就必须进行NSString-->NSDate的类型转换。

类型转换

和字段转换的实现方式一样,必须实现<MTLJSONSerializing>中的方法:

+ (NSValueTransformer *)JSONTransformerForKey:(NSString *)key;

具体实现

+ (NSValueTransformer *)JSONTransformerForKey:(NSString *)key{
    if ([key isEqualToString:@"createDate"]) {
        return [MTLValueTransformer reversibleTransformerWithForwardBlock:^id(NSString *string) {
            //NSString-->NSDate
            return [self.dateFormatter dateFromString:string];
        } reverseBlock:^id(NSDate *date) {
            //NSDate-->NSString
             return [self.dateFormatter stringFromDate:date];
        }];
    }
    else{
        return nil;
    }
}
+ (NSDateFormatter *)dateFormatter {
    NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
    dateFormatter.dateFormat = @"yyyy-MM-dd";
    return dateFormatter;
}

API:

+ (instancetype)reversibleTransformerWithForwardBlock:(MTLValueTransformerBlock)forwardBlock reverseBlock:(MTLValueTransformerBlock)reverseBlock;

第一个Block的返回的值是字典-->模型转换的结果,第二Block的返回值是模型-->字典转换的结果。当然如果我们只需要序列化,那么就实现单向转换即可,使用下列API:

+ (instancetype)reversibleTransformerWithBlock:(MTLValueTransformerBlock)transformationBlock;

Mantle其实还提供了另一种实现方式,同样的实现上述功能

+ (NSValueTransformer *)createDateJSONTransformer{
return [MTLValueTransformer reversibleTransformerWithForwardBlock:^id(NSString *string) {
            return [self.dateFormatter dateFromString:string];
        } reverseBlock:^id(NSDate *date) {
             return [self.dateFormatter stringFromDate:date];
        }];
}

方法命名规则是:+<key>JSONTransformer,另外对于BOOL和NSURL类型的有更快捷的方法:

+ (NSValueTransformer *)urlJSONTransformer{
    return [NSValueTransformer valueTransformerForName:MTLURLValueTransformerName];
}
+ (NSValueTransformer *)isVipJSONTransformer{
    return [NSValueTransformer valueTransformerForName:MTLBooleanValueTransformerName];
}

最后关于age字段的转换

+ (NSValueTransformer *)ageJSONTransformer{
    return [MTLValueTransformer reversibleTransformerWithForwardBlock:^id(NSString *string) {
        return @([string integerValue]);
    } reverseBlock:^id(NSNumber *number) {
        return [number stringValue];
    }];
}

不要问我为什么返回的是NSNumber类型也可以

空对象处理

先来看一段代码

    NSDictionary *response = @{@"id" : @"1",
                          @"phone" : @"xxxxxx",
                          @"date" : @"2014-09-09",
                          @"goldNumber" : @2,
                          @"age" : @"18",
                          @"url" : @"http://bawn.github.io/",
                          @"isVip" : NSNull.null
                          };
    Member *member = [MTLJSONAdapter modelOfClass:[Member class] fromJSONDictionary:response error:nil];

这里模拟的是服务端返回空的isVip字段对应的值,运行的结果当然是crash,Mantle也为这种情况提供了解决办法,实现Mantle内部会把值转换为nil,然后需要我们去实现- (void)setNilValueForKey:(NSString *)key;方法即可

Member.m

- (void)setNilValueForKey:(NSString *)key{
    if ([key isEqualToString:@"isVip"]) {
        self.isVip = 0;
    }
    else{
        [super setNilValueForKey:key];
    }
}

这种问题其实只针对于非指针类型,像float,bool,double。

Core Data相关

Mantle还提供了一个专门操作Core Data的协议<MTLManagedObjectSerializing>,其中包括有些非常有用的方法,比如:唯一性检查、实体属性转换等。下一篇博文我将着重讲述MagicalRecord配合Mantle的使用。

最后

Mantle当然还有其他一些功能
* 归档:已实现了NSCoding协议
* 比较:- (BOOL)isEqual:(id)object;,默认实现-hash

Demo地址:MagicalRecord-Mantle

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值