[转]oc中Mantle的使用

转载自:胜利哥的江湖 的 Mantle的使用

传统的写法是多么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];
}

注:这篇文章大部分翻译自Mantle

Leave a Reply

Your email address will not be published. Required fields are marked *