更新备注:现在我在项目里都用 YYModel 了,Mantle 不怎么用了。供参考。
本来觉得前面应该简单说一下它能够简化的东西,后来想想,能搜到这里的肯定知道它是什么。还是简单写一下:
官方解释:
Mantle makes it easy to write a simple model layer for your Cocoa or Cocoa Touch application.
Mantle 帮助我们简化了 Cocoa & Cocoa Touch 的 Model
层。
一般来说我们的做 Model 层的开发经常要完成如下工序:
- 做 Model 层的东西动不动就定义一堆 Property ( 其实使用Mantle也得定义...嗯...我也不知道我为什么写这条)
- 「重点」从服务器获得 JSON 串之后要手写一个 ParseToMyModel 这么一个方法,这个方法接受一个 Dict,返回一个
MyModel *myModel
,十分难写。 - Submit 本地的 Model 的时候,自己得拼一个 JSON 吧......
- 要归档...嗯...
- (void)encodeWithCoder:(NSCoder *)coder;
- 归档了之后,还要...嗯...
- (id)initWithCoder:(NSCoder *)coder;
我司小项目有10个自定义的 Model ...一个一个地写这么多,多 low 啊 ...想想人家 俄罗斯的工程师大神 !这种东西写到第二遍的时候是不是就应该去封装优化啦?
Mantle的出现其实就解决了上面的问题。
马上零点了,好困,赶紧写完睡觉了。。。
快速集成
Step 1:pod 引入
一定要用 CocoaPods,别手动拖进去,好麻烦的说。
pod 'Mantle', '~> 2.0.4'
Step 2:创建适用于 Mantle 的 Model
哦,我司后台妹子下午刚刚给我了个这个 JSON:
{
"create_time":"2015-11-26 16:38:03.0",
"create_user":"81",
"order_id":"1448527083280",
"order_status":"0",
"pay_status":"1",
"payment":"0.50",
"remerk":"",
"storeAddress":"",
"userOrderId":"201511264820"
}
然后是不是要根据这个创建 Model 呀。
New File -> Cocoa Class -> PSOrder(YourModelName)
这里的 SubClass 填上 MTLModel
。
哦,这篇用的语言是 OC,好久没写 OC 啦~
创建完了时候在 .h
文件中 #import
#import "MTLModel.h"
然后还要遵守一个Procotol <MTLJSONSerializing>
。
@interface PSOrder : MTLModel <MTLJSONSerializing>
然后就是要把所有的属性写出来,我使用的是 Xcode 插件 ESJsonFormat
直接生成一堆 @property,但是 strong assign weak copy readonly 修饰符什么的还是自己要对一下,根据你 Model 的需求来。
然后把 iVar 们的命名觉得有必要的稍微改改,你看看这个 order_id
符合 iOS 变量命名规范吗。
@property (nonatomic, copy, readonly) NSString *remerk;
@property (nonatomic, copy, readonly) NSString *orderID;
@property (nonatomic, copy, readonly) NSString *createUser;
@property (nonatomic, copy, readonly) NSString *orderStatus;
@property (nonatomic, copy, readonly) NSString *payment;
@property (nonatomic, copy, readonly) NSString *storeAddress;
@property (nonatomic, copy, readonly) NSString *userOrderId;
@property (nonatomic, copy, readonly) NSString *createDate;
@property (nonatomic, copy, readonly) NSString *payStatus;
先这样,然后之前遵守的Procotol <MTLJSONSerializing>
就要登场啦,
+ (NSDictionary *)JSONKeyPathsByPropertyKey {
return @{
@"payStatus": @"pay_status",
@"orderID": @"order_id",
@"createUser": @"create_user",
@"orderStatus": @"order_status",
@"payment": @"payment",
@"storeAddress": @"storeAddress",
@"userOrderId": @"userOrderId",
@"createDate": @"create_time",
@"payStatus": @"pay_status",
@"remark": @"remerk"};
}
凭你深厚的 iOS 开发程序员的慧眼你应该能看出来这个是干嘛的,这个方法提供了一个 Dict 作为 Mantle 的 Map 映射。
有了这个 Dict 之后呢,Mantle 就知道 JSON 里面的某个键值对对应的是 Model 里面的哪个 property 了。
其实还有另外一个好处,你想,如果你的项目写到了足够后期,即使这个时候 Server 端要把返回的一个 remark 改成 remark,你只需要修改映射表一个地方就 OK 辣,别的地方都不需要修改。
嗯。
Step 3:Mantle Model 的生成
你的 Request 模块拿到了 JSON 字符串之后呢......算了直接给你看代码:
for (NSDictionary* orderDict in dic[@"data"]) {
NSError* error;
PSOrder* order = [MTLJSONAdapter modelOfClass:[PSOrder class] fromJSONDictionary:orderDict error:&error];
if(error){
NSLog(@"error:%@, Info:%@",error,error.userInfo);
}
[searchResults addObject:order];
}
核心代码:
PSOrder* order = [MTLJSONAdapter modelOfClass:[PSOrder class] fromJSONDictionary:orderDict error:&error];
如果没问题的话,这里的 order 对象就已经成功转换成功了。
对了可以把生成好的 model 对象 NSLog 出来,发现成功转化成 JSON 字符串了,很方便了对象的上传操作。
这就是 Mantle 的简单用法快速上手。后期更加高级的用法在做补充,整个Mantle很值得研究,而且有很多工具类,值得满满深入研究。
简单提一下实现原理
Mantle 的实现原理其实特别简单,你想,它唯一还没有被优化的是 @Property 还得手写,当然这个可能后期也不太好优化,因为 iVar 的修饰符涉及项目的业务需求,所以是多变的。
从这点入手,Mantle 拿到了JSON,是不是知道所有的 Key 列表,假设你 Model 的所有 property 都没写错的话,所有的映射都做好了。Mantle 可以使用 Runtime 和 KVC 去把 JSON 串里面值一个一个地塞进到你的 MTLModel 里面。
所以实现的原理最核心最重要的就是两个:
- Runtime 的 propertyList
- KVC