传统的写法是多么low
做iOS开发的,大概都写过model类。入门的写法大家可以参考Afnetworking的Demo,有一个较经典的例子。 当项目规模变得越来越大后,你会发现,传统的写法成本会很高,维护成本也很高。 用mantle,可以用很小的开发维护成本获得最大的开发效率。用mantle可以很方便的进行模型类和JSON数据之间的转换。
(还有其他理由说服我使用mantle吗?) Mantle是github公司创建和维护的,并且用在了自己的产品中;还有twitter也在使用。这些理由够不够???
入门教程
1.创建类
必须继承MTLModel类,并实现MTLJSONSerializing协议。 每一个model都要从MTLModel类继承,并实现 +(NSDictionary *)JSONKeyPathsByPropertyKey;方法,该方法是用来对应NSDictionary中Key与属性关系的。
举个例子:
{ "id": 1, "name": "Objective Dog", "birthday": "2015-09-12 13:29:36 +0100", "website": "http://g.cn", "location": { "lat": "48.2083", "lon": "16.3731" }, "relationship_status": "single", "awesome": true }
我们现在对这个JSON数据进行转换。
// .h typedef NS_ENUM(NSInteger, CATRelationshipStatus) { CATRelationshipStatusSingle = 0, CATRelationshipStatusInRelationship, CATRelationshipStatusComplicated }; @interface CATProfile : MTLModel<MTLJSONSerializing> @property(strong, nonatomic) NSNumber *profileId; @property(strong, nonatomic) NSString *name; @property(strong, nonatomic) NSDate *birthday; @property(strong, nonatomic) NSURL *website; @property(nonatomic) CLLocationCoordinate2D locationCoordinate; @property(nonatomic) CATRelationshipStatus relationshipStatus; @property(nonatomic, getter=isAwesome) BOOL awesome; @end // .m @implementation + (NSDictionary *)JSONKeyPathsByPropertyKey { // properties defined in header < : > key in JSON Dictionary return @{ @"profileId": @"id", @"websiteURL": @"website", @"locationCoordinate": @"location", @"relationshipStatus": @"relationship_status", }; } @end
+JSONKeyPathsByPropertyKey 方法返回一个JSON key与model属性一一对应的字典。这样,mantle才能进行转换。
2.值转换
日期转换
Mantle可以对NSString,NSNumber等类型进行自动转换,但对于enum类型,NSUrl,boolean,或者自定义的类型,需要进行手工指定转换。
转换的办法就是对每一个需要转换的属性,实现一个方法。具体的格式如下: +JSONTransformer,返回NSValueTransformer类型的数据。
+ (NSValueTransformer *)birthdayJSONTransformer { return [MTLValueTransformer reversibleTransformerWithForwardBlock:^(NSString *dateString) { return [self.dateFormatter dateFromString:dateString]; } reverseBlock:^(NSDate *date) { return [self.dateFormatter stringFromDate:date]; }]; } + (NSDateFormatter *)dateFormatter { NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init]; dateFormatter.locale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"]; dateFormatter.dateFormat = @"yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"; return dateFormatter; }
NSUrl ↔ NSString 之间的转换
+ (NSValueTransformer *)websiteURLJSONTransformer { return [NSValueTransformer valueTransformerForName:MTLURLValueTransformerName]; }
CLLocationCoordinate2D ↔︎ JSON object
+ (NSValueTransformer *)locationCoordinateJSONTransformer { return [MTLValueTransformer reversibleTransformerWithForwardBlock:^(NSDictionary *coordinateDict) { CLLocationDegrees latitude = [coordinateDict[@"lat"] doubleValue]; CLLocationDegrees longitude = [coordinateDict[@"lon"] doubleValue]; return [NSValue valueWithMKCoordinate:CLLocationCoordinate2DMake(latitude, longitude)]; } reverseBlock:^(NSValue *coordinateValue) { CLLocationCoordinate2D coordinate = [coordinateValue MKCoordinateValue]; return @{@"lat": @(coordinate.latitude), @"lon": @(coordinate.longitude)}; }]; }
enum ↔︎ JSON string
+ (NSValueTransformer *)relationshipStatusJSONTransformer { return [NSValueTransformer mtl_valueMappingTransformerWithDictionary:@{ @"single": @(CATRelationshipStatusSingle), @"relationship": @(CATRelationshipStatusInRelationship), @"complicated": @(CATRelationshipStatusComplicated) }]; }
BOOL ↔︎ JSON boolean
+ (NSValueTransformer *)awesomeJSONTransformer { return [NSValueTransformer valueTransformerForName:MTLBooleanValueTransformerName]; }
3.将json数据转换成model对象
// create NSDictionary from JSON data NSData JSONData = ... // the JSON response from the API NSDictionary *JSONDict = [NSJSONSerialization JSONObjectWithData:JSONData options:0 error:NULL]; // create model object from NSDictionary using MTLJSONSerialisation CATProfile *profile = [MTLJSONAdapter modelOfClass:CATProfile.class fromJSONDictionary:JSONDict error:NULL];
4.将model对象转化成json
// create NSDictionary from model class using MTLJSONSerialisation CATProfile *profile = ... NSDictionary *profileDict = [MTLJSONAdapter JSONDictionaryFromModel:profile]; // convert NSDictionary to JSON data NSData *JSONData = [NSJSONSerialization dataWithJSONObject:profileDict options:0 error:NULL];
如果model中包含一些属性,这些属性不是从json数据中转换来的。这时候,你需要做些设置,防止mantle在把model转成json时,转换这些属性。
+ (NSDictionary *)JSONKeyPathsByPropertyKey { return @{ @"UUID": @"id", @"someProp": @"some_prop", @"anotherProp": @"another", @"myInternalProperty": NSNull.null, @"myAnotherInternalProperty": NSNull.null, }; }
5.数组和字典的转换
数组和字典值,使我们经常会遇到的json结构。Mantle帮我们做了很多工作,让我们很轻松的进行转换。
{ "id": 1, "name": "Objective Cat", ..., "owner": { "id": 99, "name": "Alexander Schuch" }, "friends": [ { "name": "Owly", "type": "bird" }, { "name": "Hedgy", "type": "mammal" } ] }
Mantle提供了2个方法进行转换:
+ (NSValueTransformer *)mtl_JSONDictionaryTransformerWithModelClass:(Class)modelClass; + (NSValueTransformer *)mtl_JSONArrayTransformerWithModelClass:(Class)modelClass;
看例子:
// CATProfile.h @property(strong, nonatomic) CATOwner *owner; // CATOwner is a MTLModel subclass @property(strong, nonatomic) NSArray *friends; // Array of CATFriend objects // CATProfile.m + (NSValueTransformer *)ownerJSONTransformer { return [NSValueTransformer mtl_JSONDictionaryTransformerWithModelClass:CATOwner.class]; } + (NSValueTransformer *)friendsJSONTransformer { return [NSValueTransformer mtl_JSONArrayTransformerWithModelClass:CATFriend.class]; }