如何使用Mantle省略JSON字典中的空值?

时间:2013-09-23 14:18:22

标签: ios github-mantle

我有从MTLModel继承的MyModel(使用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

现在我想使用AFNetworking将JSON发送到后端。在此之前,我将模型实例转换为JSON NSDictionary,以在我的请求中用作参数/主体有效负载。

NSDictionary *JSON = [MTLJSONAdapter JSONDictionaryFromModel:myModel];

但是这个JSON包含奇怪的“”字符串,用于我的模型属性为零。我想要的是Mantle省略这些键/值对,只吐出一个只有非零或NSNull.null属性的JSON,无论如何。

4 个答案:

答案 0 :(得分:37)

这是Mantle的一个常见问题,它被称为隐式JSON映射

MTLJSONAdapter读取模型的所有属性以创建JSON字符串,可选择用+JSONKeyPathsByPropertyKey中给出的属性名称替换属性名称。

如果您希望从模型的JSON表示中排除某些属性,请将它们映射到NSNull.null中的+JSONKeyPathsByPropertyKey

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

隐式JSON映射最近成为一个值得注意的问题,目前正在GantHub的Mantle家庭存储库中讨论解决方案。

查看问题#137#138#143以及 #149 下的当前讨论。


编辑:我明显误解了这个问题,但现在,当我认为我理解正确时,答案很简单。

MTLJSONAdapter使用MTLModel的{​​{1}}属性生成JSON数据。如果您希望从JSON本身中排除某个属性,则可以在dictionaryValue中覆盖该方法:

MYModel

编辑#2:查看代码*以删除- (NSDictionary *)dictionaryValue { NSMutableDictionary *originalDictionaryValue = [[super dictionaryValue] mutableCopy]; if (self.aPropertyThatShouldBeExcludedWhenNil == nil) { [originalDictionaryValue removeObjectForKey:@"aPropertyThatShouldBeExcludedWhenNil"]; } /* repeat the process for other "hidden" properties */ return originalDictionaryValue; } 的所有值:

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]; }

答案 1 :(得分:1)

我通过创建 MTLJSONAdapter子类并覆盖-serializablePropertyKeys:forModel:方法来删除无值键。

MTLJSONAdapterWithoutNil.h

/** A MTLJSONAdapter subclass that removes model dictionaryValue keys whose value is `[NSNull null]`. */
@interface MTLJSONAdapterWithoutNil : MTLJSONAdapter
@end

MTLJSONAdapterWithoutNil.m

#import "MTLJSONAdapterWithoutNil.h"

@implementation MTLJSONAdapterWithoutNil

- (NSSet *)serializablePropertyKeys:(NSSet *)propertyKeys forModel:(id<MTLJSONSerializing>)model {
    NSMutableSet *ms = propertyKeys.mutableCopy;
    NSDictionary *modelDictValue = [model dictionaryValue];
    for (NSString *key in ms) {
        id val = [modelDictValue valueForKey:key];
        if ([[NSNull null] isEqual:val]) { // MTLModel -dictionaryValue nil value is represented by NSNull
            [ms removeObject:key];
        }
    }
    return [NSSet setWithSet:ms];
}

@end

并使用它来创建JSON字典。像这样:

NSDictionary *JSONDictionary = [MTLJSONAdapterWithoutNil JSONDictionaryFromModel:collection error:nil];

注意: 如果要覆盖数组或字典属性的NSValueTransformer方法,还必须将MTLJSONAdapter类更改为子类。< / strong>喜欢这个:

+ (NSValueTransformer *)myDailyDataArrayJSONTransformer {
    return [MTLJSONAdapterWithoutNil arrayTransformerWithModelClass:KBDailyData.class];
}

答案 2 :(得分:0)

重写 - dictionaryValues没有给我预期的行为

所以我为MTL Base类创建了一个方法

    - (NSDictionary *)nonNullDictionaryWithAdditionalParams:(NSDictionary *)params error:(NSError *)error {
        NSDictionary *allParams = [MTLJSONAdapter JSONDictionaryFromModel:self error: &error];
        NSMutableDictionary *modifiedDictionaryValue = [allParams mutableCopy];

        for (NSString *originalKey in allParams) {
            if ([allParams objectForKey:originalKey] == NSNull.null) {
                [modifiedDictionaryValue removeObjectForKey:originalKey];
            }
        }

        [modifiedDictionaryValue addEntriesFromDictionary:params];
        return [modifiedDictionaryValue copy];
    }

答案 3 :(得分:-1)

编辑#2过去常常使用之前的Mantle代码库。现在我必须执行以下操作继续使用EDIT#2:

在文件MTLJSONAdapter.m中,替换此行:

NSDictionary *dictionaryValue = [model.dictionaryValue dictionaryWithValuesForKeys:propertyKeysToSerialize.allObjects];

NSDictionary *dictionaryValue = model.dictionaryValue;

以上是我目前的解决方法

{ }

而不是

{
  "AddressLine2" : null,
  "City" : null,
  "ZipCode" : null,
  "State" : null,
  "AddressLine1" : null
}