MagicalMaping—iOS对象映射

iOS网络请求到的json数据需要手动setter/getter序列化到具体的model对象,但这种写法就觉得不太优美,有时候model对象重用的时候还要重复的写setter。询问小伙伴,推荐一个名为jastor的对象序列化库,这个库可以序列化普通对象,但是对NSDate和CoreData的支持不完美或者说根本不支持。另外Restkit一大亮点也是支持对象自动映射,可同样不支持CoreData对象,况且Restkit框架还不够成熟。
参考Restkit对象映射的设计风格以及jastor对runtime的处理方式,我自己封装了一个映射库:magicalMapping. 支持coredata和NSDate的序列化。

######用法:
一.导入文件,添加CoreData.framework框架. ARC的项目需要做编译处理(-fno-objc-arc)
二.新建一个班级对象ClassObj(示例)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#import <Foundation/Foundation.h>
#import "TeacherObj.h"
@interface ClassObj : NSObject
@property(nonatomic,copy)NSString *className;
@property(nonatomic,retain)NSNumber *studentsCount;
@property(nonatomic,assign)NSNumber *isGoodClass;
@property(nonatomic,copy)NSString *leaderName;
@property(nonatomic,retain)NSDate *createDate;
@property(nonatomic,retain)NSArray *studentMembers;
@property(nonatomic,retain)TeacherObj *teacher;
@end

#import "ClassObj.h"

@implementation ClassObj
-(NSDictionary *)propertyNameMapping
{
return @{@"name":@"className",
@"count":@"studentsCount",
@"isGoodClass":@"isGoodClass",
@"leaderName":@"leaderName",
@"createDate":@"createDate",
@"students":@"studentMembers",
@"englishTeacher":@"teacher"
};
}
-(NSDictionary *)propertyTypeFormat
{
return @{@"createDate":@"yyyy-MM-dd HH:mm",
@"studentMembers":@"StudentObj",
@"teacher":@"TeacherObj"
};

}
@end

.m文件中propertyNameMapping方法返回一个映射字典,其中key代表json中对象的字段名称,而value代表ClassObj对象属性名称,这里的值必须和对象的属性值一样。其实对象映射完全可以通过runtime api 动态获取对象的属性然后进行赋值映射,可这样带来的坏处就是如果解析出来的json有一个字段为description, 而description是NSObject的保留字,赋值当然也就会失败。所以手动创新对象映射字典的好处就是可以保证model对象的属性名和json对象的字段名称可以不一致。

propertyTypeFormat方法是为了处理NSDate和复杂属性而设置的。例如ClassObj有个属性studentMembers,它是数组类型。当数组为空时runtime也没法知道里面到底存取什么类型的对象,所以需要人工指定。json返回的日期为string类型,映射为NSDate是需要指定NSDateFormatter的格式,所以使用了”createDate”:@”yyyy-MM-dd HH:mm”. (关于这一点我也很惆怅,通过正则表达式可以自动判断出NSDateFormatter,可公司的服务器编程老喜欢返回不同格式的date字符串,而且毫无规律可言。所以这个字段就手工设置NSDateFormatter好了)

创建coredata对象时,推荐使用Mogenerator(教程见文章底部链接),这样就不必每次重建model都要重新写propertyNameMapping和propertyTypeFormat方法了。

三。设置完对象后,下面进行映射 ,json解析用的是jsonkit

1
2
3
4
5
NSURL * url =[NSURL fileURLWithPath:[[NSBundle mainBundle]pathForResource:@"data" ofType:@"json"]];
NSData *jsonData =[NSData dataWithContentsOfURL:url];
NSDictionary *jsonDic =[jsonData objectFromJSONData];
ClassObj *classObj =[[ClassObj alloc]init];
[classObj configMappingWithDictionary:jsonDic managerObjectContext:nil];

另外 magicalMapping基于KVC,所以model的必须使用规范化的命名,如bool,int,doube等类型必须使用NSNumber替代(这在coredata中都是自动实现的),但是普通model中除了bool类型,其它定义为int,double类型的好像也映射成功了。

大家有兴趣的可以下载看看,也希望提出宝贵意见。新浪微博 @Nidom

完整demo

https://github.com/nidom/magicalMapping

Mogenerator的使用

http://www.cocoachina.com/bbs/read.php?tid=143640

http://rentzsch.github.com/mogenerator/