objective-cgithub-mantle

Combine multiple keys into single property using Mantle


I am receiving multiple keys for Latitude and Longitude in the JSON body for a request.

{
  ...
  latitude: "28.4949762000",
  longitude: "77.0895421000"
}

I would like to combine them into a single CLLocation property while converting them into my JSON model:

#import <Mantle/Mantle.h>
@import CoreLocation;

@interface Location : MTLModel <MTLJSONSerializing>

@property (nonatomic, readonly) float latitude;
@property (nonatomic, readonly) float longitude;       //These are the current keys

@property (nonatomic, readonly) CLLocation* location;  //This is desired

@end

How do I go about achieving the same?


Solution

  • Finally found the answer here. It's quite an ingenious way, and I was surprised to see it not being mentioned in the docs explicitly.

    The way to combine multiple keys into a single object is by mapping the target property to multiple keys using an array in the +JSONKeyPathsByPropertyKey method. When you do so, Mantle will make the multiple keys available in their own NSDictionary instance.

    +(NSDictionary *)JSONKeyPathsByPropertyKey
    {
        return @{
                 ...
                 @"location": @[@"latitude", @"longitude"]
                 };
    }
    

    If the target property is an NSDictionary, you're set. Otherwise, you will need specify the conversion in either the +JSONTransformerForKey or the +propertyJSONTransformer method.

    +(NSValueTransformer*)locationJSONTransformer
    {
        return [MTLValueTransformer transformerUsingForwardBlock:^CLLocation*(NSDictionary* value, BOOL *success, NSError *__autoreleasing *error) {
    
            NSString *latitude = value[@"latitude"];
            NSString *longitude = value[@"longitude"];
    
            if ([latitude isKindOfClass:[NSString class]] && [longitude isKindOfClass:[NSString class]])
            {
                return [[CLLocation alloc] initWithLatitude:[latitude floatValue] longitude:[longitude floatValue]];
            }
            else
            {
                return nil;
            }
    
        } reverseBlock:^NSDictionary*(CLLocation* value, BOOL *success, NSError *__autoreleasing *error) {
    
            return @{@"latitude": value ? [NSString stringWithFormat:@"%f", value.coordinate.latitude] : [NSNull null],
                     @"longitude": value ? [NSString stringWithFormat:@"%f", value.coordinate.longitude]: [NSNull null]};
        }];
    }