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

Ios 如何使用Mantle在JSON字典中省略空值?,ios,github-mantle,Ios,Github Mantle,我的模型继承自MTLModel(使用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 (

我的模型继承自MTLModel(使用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
现在我想使用AFNetworking将JSON发送到后端。在此之前,我将模型实例转换为JSON NSDictionary,用作请求中的参数/正文负载

NSDictionary *JSON = [MTLJSONAdapter JSONDictionaryFromModel:myModel];

但是这个JSON由奇怪的“”字符串组成,这些字符串表示我的模型的属性为零。相反,我希望Mantle忽略这些键/值对,只输出一个属性不是nil或NSNull.null的JSON,不管怎样。

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

MTLJSONAdapter
读取模型的所有属性,创建一个JSON字符串,可选地将属性名称替换为
+JSONKeyPathsByPropertyKey
中给出的属性名称

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

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

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

请参阅下的问题和当前讨论


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

MTLJSONAdapter
使用
MTLModel
dictionaryValue
属性生成JSON数据。如果希望从JSON本身中排除属性,可以在
MYModel
中覆盖该方法:

- (NSDictionary *)dictionaryValue {
    NSMutableDictionary *originalDictionaryValue = [[super dictionaryValue] mutableCopy];

    if (self.aPropertyThatShouldBeExcludedWhenNil == nil) {
        [originalDictionaryValue removeObjectForKey:@"aPropertyThatShouldBeExcludedWhenNil"];
    }

    /* repeat the process for other "hidden" properties */

    return originalDictionaryValue;
}

编辑#2:检查代码*以删除所有
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];
}
*-matths建议的代码示例。

编辑#2用于我使用以前的Mantle代码库。现在,我必须执行以下操作才能继续使用EDIT#2:

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

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

以上是我目前的解决办法,以获得

{ }
而不是

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

我通过创建一个MTLJSONAdapter子类,并重写
-serializablePropertyKeys:forModel:
方法来删除无值键

MTLJSONADAPTER不带零。h

MTLJSONADAPTER不带零。m


重写-字典值没有给我预期的行为

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

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

你能发布MyModel的完整代码吗?我编辑了这个问题。因此,想象一个不完全RESTful的API。因此,在获取该模型的数据时,“some_prop”不会被传递,这将导致为零。将此模型转换回JSON时,属性将转换为“some_prop”:“”:(谢谢你的回答。我已经意识到在模型的JSON表示中排除了一些属性。但这不是一个在运行时忽略空值的解决方案,当它们为空时,但如果它们具有有效值,则包括它们。好吧,似乎我误解了这个问题。我编辑了我的答案,希望现在它将解决您的问题。;)很高兴它能工作!我添加了用于检查所有属性的代码示例,尽管我对其进行了一点改进。;)奇怪的是,编辑#2解决方案对我不起作用。dictionaryValue方法似乎从未被调用。我必须对每个可能为空的值使用值转换器。编辑#2过去对我有用。但现在最新的外套不起作用了。我看到的是类似“Address=”“;”的东西,而不是什么都没有。有人有更新的解决方案吗?谢谢!嗯,我认为您不应该直接修改Mantle framework中的文件。只有当您的属性名称与JSON密钥名称相同时,这才有意义
val
[[NSNull null]isEqual:val]
中的
val
是的,我忘记了,抱歉,编辑了。嗨@Hlung,你成功地使它适用于嵌套模型了吗?@SergiiN。我没有试过那个案子。这个解决方案行不通吗?
{
  "AddressLine2" : null,
  "City" : null,
  "ZipCode" : null,
  "State" : null,
  "AddressLine1" : null
}
/** A MTLJSONAdapter subclass that removes model dictionaryValue keys whose value is `[NSNull null]`. */
@interface MTLJSONAdapterWithoutNil : MTLJSONAdapter
@end
#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
+ (NSValueTransformer *)myDailyDataArrayJSONTransformer {
    return [MTLJSONAdapterWithoutNil arrayTransformerWithModelClass:KBDailyData.class];
}
    - (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];
    }