Mantle

Episode #116 | 16 minutes | published on April 24, 2014 | Uses mantle-1.4.1
In this episode we go over a handy little model framework called Mantle. With Mantle we can easily get support for NSCoding, NSCopying, and JSON serialization for our model objects.

Episode Links

Implementing Mantle for JSON Serialization

We need to inherit from MTLModel for equals:, hashCode, NSCoding, and NSCopying. To get JSON serialization support, we also need to conform to the MTLJSONSerializing protocol:


#import "Mantle.h"

typedef NS_ENUM(NSInteger, EpisodeType) {
    EpisodeTypePaid,
    EpisodeTypeFree
};

@interface Episode : MTLModel <MTLJSONSerializing>

@property (nonatomic, assign) NSInteger episodeNumber;
@property (nonatomic, copy) NSString *title;
@property (nonatomic, copy) NSString *episodeDescription;
@property (nonatomic, copy) NSURL *thumbnailImageUrl;
@property (nonatomic, assign) EpisodeType episodeType;
@property (nonatomic, strong) NSDate *publishedAt;

@end

Next we need to provide a mapping for our keys. Names that match up directly are copied automatically, but we have to specify the deviations:

+ (NSDictionary *)JSONKeyPathsByPropertyKey {
    return @{
             @"episodeDescription": @"description",
             @"episodeNumber" : @"episode_number",
             @"episodeType" : @"episode_type",
             @"publishedAt" : @"published_at",
             @"thumbnailImageUrl" : @"thumbnail_url"
             };
}

For the type conversions, such as enums, urls, or dates, you must specify a value transformer. Keep in mind that we can serialize in both directions, so some of these transformers can be specified as reversible.

+ (NSValueTransformer *)episodeTypeJSONTransformer {
    return [NSValueTransformer mtl_valueMappingTransformerWithDictionary:@{
                                                                           @"paid": @(EpisodeTypePaid),
                                                                           @"free": @(EpisodeTypeFree)
                                                                           }];
}

+ (NSDateFormatter *)dateFormatter {
    static NSDateFormatter *__dateFormatter = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        __dateFormatter = [[NSDateFormatter alloc] init];
        __dateFormatter.locale = [NSLocale localeWithLocaleIdentifier:@"en_US_POSIX"];
        __dateFormatter.dateFormat = @"yyyy-MM-dd'T'HH:mm:ssZ";
    });
    return __dateFormatter;
}

+ (NSValueTransformer *)publishedAtJSONTransformer {
    return [MTLValueTransformer transformerWithBlock:^id(NSString *dateString) {
        return [self.dateFormatter dateFromString:dateString];
    }];
}

+ (NSValueTransformer *)thumbnailImageUrlJSONTransformer {
    return [NSValueTransformer valueTransformerForName:MTLURLValueTransformerName];
}

The thing to notice here is that the name of these methods is dynamic, and is the combination of your property key and the value "JSONTransformer". If you don't specify a transformer, it will try to copy the value over directly, which could end in a crash if the types don't match up.

blog comments powered by Disqus