做iOS开发的,大概都写过model类。入门的写法大家可以参考Afnetworking的Demo,有一个较经典的例子。 当项目规模变得越来越大后,你会发现,传统的写法成本会很高,维护成本也很高。 用mantle,可以用很小的开发维护成本获得最大的开发效率。用mantle可以很方便的进行模型类和JSON数据之间的转换。
(还有其他理由说服我使用mantle吗?) Mantle是github公司创建和维护的,并且用在了自己的产品中;还有twitter也在使用。这些理由够不够???
必须继承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才能进行转换。
Mantle可以对NSString,NSNumber等类型进行自动转换,但对于enum类型,NSUrl,boolean,或者自定义的类型,需要进行手工指定转换。
转换的办法就是对每一个需要转换的属性,实现一个方法。具体的格式如下:
+
+ (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;
}
+ (NSValueTransformer *)websiteURLJSONTransformer {
return [NSValueTransformer valueTransformerForName:MTLURLValueTransformerName];
}
+ (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)};
}];
}
+ (NSValueTransformer *)relationshipStatusJSONTransformer {
return [NSValueTransformer mtl_valueMappingTransformerWithDictionary:@{
@"single": @(CATRelationshipStatusSingle),
@"relationship": @(CATRelationshipStatusInRelationship),
@"complicated": @(CATRelationshipStatusComplicated)
}];
}
+ (NSValueTransformer *)awesomeJSONTransformer {
return [NSValueTransformer valueTransformerForName:MTLBooleanValueTransformerName];
}
// 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];
// 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,
};
}
数组和字典值,使我们经常会遇到的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];
}