iosgithub-mantle

How to omit null values in JSON Dictionary using Mantle?


I have MyModel inheriting from MTLModel (using the GitHub Mantle pod). MyModel.h

#import <Mantle/Mantle.h>
@interface MyModel : MTLModel <MTLJSONSerializing>
@property (nonatomic, copy, readonly) NSString *UUID;
@property (nonatomic, copy) NSString *someProp;
@property (nonatomic, copy) NSString *anotherProp;
@end

MyModel.m

#import "MyModel.h"
@implementation MyModel
+ (NSDictionary *)JSONKeyPathsByPropertyKey
{
        return @{
            @"UUID": @"id",
            @"someProp": @"some_prop",
            @"anotherProp": @"another"
    };
}
}
@end

Now I want to send the JSON to the backend using AFNetworking. Before that I convert the model instance to a JSON NSDictionary to use as parameters/body payload within my request.

NSDictionary *JSON = [MTLJSONAdapter JSONDictionaryFromModel:myModel];

But this JSON consists of strange "" Strings for properties of my model that are nil. What i instead want is Mantle to omit these key/value pairs and just spit out a JSON with only the properties that are not nil or NSNull.null, whatever.


Solution

  • This is a common issue with Mantle and it's called implicit JSON mapping.

    MTLJSONAdapter reads all properties of a model to create a JSON string optionally replacing property names with ones given in +JSONKeyPathsByPropertyKey.

    If you want some properties to be excluded from the JSON representation of your model, map them to NSNull.null in your +JSONKeyPathsByPropertyKey:

    + (NSDictionary *)JSONKeyPathsByPropertyKey {
        return @{
            @"UUID": @"id",
            @"someProp": @"some_prop",
            @"anotherProp": @"another",
            @"myInternalProperty": NSNull.null,
            @"myAnotherInternalProperty": NSNull.null,
        };
    }
    

    The implicit JSON mapping has lately become a noticeable problem, a solution for which is currently being discussed at Mantle's home repository at GitHub.

    See issues #137, #138, #143 and the current discussion under #149.


    EDIT: I clearly misunderstood the question, but now, when I suppose I understand it correctly, the answer is simple.

    MTLJSONAdapter generates the JSON data using MTLModel's dictionaryValue property. If you wish to exclude a property from the JSON itself, you can overwrite that method in your MYModel:

    - (NSDictionary *)dictionaryValue {
        NSMutableDictionary *originalDictionaryValue = [[super dictionaryValue] mutableCopy];
    
        if (self.aPropertyThatShouldBeExcludedWhenNil == nil) {
            [originalDictionaryValue removeObjectForKey:@"aPropertyThatShouldBeExcludedWhenNil"];
        }
    
        /* repeat the process for other "hidden" properties */
    
        return originalDictionaryValue;
    }
    

    EDIT #2: Check out the code* for removing all values that are nil:

    - (NSDictionary *)dictionaryValue {
        NSMutableDictionary *modifiedDictionaryValue = [[super dictionaryValue] mutableCopy];
    
        for (NSString *originalKey in [super dictionaryValue]) {
            if ([self valueForKey:originalKey] == nil) {
                [modifiedDictionaryValue removeObjectForKey:originalKey];
            }
        }
    
        return [modifiedDictionaryValue copy];
    }
    

    * - code sample suggested by matths.