【问题标题】:How to omit null values in JSON Dictionary using Mantle?如何使用 Mantle 在 JSON 字典中省略空值?
【发布时间】:2013-09-23 14:18:21
【问题描述】:

我的 MyModel 继承自 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

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 包含奇怪的“”字符串,用于我的模型的属性,它们是 nil。相反,我想要的是 Mantle 省略这些键/值对,只吐出一个 JSON,其中只有非 nil 或 NSNull.null 的属性。

【问题讨论】:

  • 你能发布 MyModel 的完整代码吗?
  • 我编辑了这个问题。所以想象一个不完全 RESTful 的 API。因此,当获取该模型的数据时,“some_prop”将不会被传递,这导致为零。将此模型转换回 JSON 时,该属性将转换为 "some_prop": "" :(

标签: ios github-mantle


【解决方案1】:

这是 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 映射最近已成为一个值得注意的问题,目前正在 Mantle 在 GitHub 的主存储库中讨论解决方案。

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


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

MTLJSONAdapter 使用MTLModeldictionaryValue 属性生成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];
}

* - code sample suggested by matths.

【讨论】:

  • 感谢您的回答。而且我已经意识到这种从模型的 JSON 表示中排除某些属性的情况。但这不是一个解决方案,当它们为空时,在运行时忽略空值,但如果它们具有有效值,则包括它们。
  • 好的,我好像误解了这个问题。我编辑了我的答案,希望这次能解决您的问题。 ;)
  • 很高兴它正在工作!我添加了用于检查所有属性的代码示例,尽管我对其进行了一些改进。 ;)
  • 奇怪的是,EDIT #2 解决方案对我不起作用。 dictionaryValue 方法似乎永远不会被调用。我必须对每个可能为空的值使用值转换器。
  • EDIT #2 曾经为我工作。但是现在有了最新的 Mantle,它就不起作用了。我看到类似“地址=”“;”而不是什么都没有。有人有更新的解决方案吗?谢谢!
【解决方案2】:

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

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 类更改为您的子类。 喜欢这个:

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

【讨论】:

  • [[NSNull null] isEqual:val] 中的val 是什么?
  • 你好像忘了说val = modelDictValue[key]
  • 是的,我忘记了,抱歉 T_T。已编辑。
  • 嗨@Hlung 你成功让它适用于嵌套模型了吗?
  • @SergiiN。我没有试过那种情况。这个解决方案不起作用吗?
【解决方案3】:

覆盖 - dictionaryValues 没有给我预期的行为

所以我为 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];
    }

【讨论】:

    【解决方案4】:

    EDIT #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
    }
    

    【讨论】:

    • 嗯,我认为你不应该直接修改Mantle框架中的文件。
    • 只有当您的属性名称与 JSON 键名称相同时才有意义
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-11-27
    • 1970-01-01
    • 2020-02-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多