Как опустить нулевые значения в словаре JSON с помощью мантии?
У меня есть 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
Теперь я хочу отправить JSON на бэкэнд, используя AFNetworking. До этого я конвертирую экземпляр модели в JSON NSDictionary для использования в качестве параметров/полезной нагрузки тела в моем запросе.
NSDictionary *JSON = [MTLJSONAdapter JSONDictionaryFromModel:myModel];
Но этот JSON состоит из странных "строк" для свойств моей модели, которые равны нулю. То, что я вместо этого хочу, это Mantle, чтобы опустить эти пары ключ/значение и просто выплюнуть JSON только с свойствами, которые не ноль или NSNull.null, что бы то ни было.
Ответы
Ответ 1
Это обычная проблема с 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 в последнее время стало заметной проблемой, решение для которой в настоящее время обсуждается в репозитории Mantle home в GitHub.
См. вопросы # 137, # 138, # 143 и текущее обсуждение под # 149.
РЕДАКТИРОВАТЬ: Я четко не понял этот вопрос, но теперь, когда я полагаю, что я правильно его понимаю, ответ прост.
MTLJSONAdapter
генерирует данные JSON с использованием свойства MTLModel
dictionaryValue
. Если вы хотите исключить свойство из самого 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;
}
EDIT # 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.
суб >
Ответ 2
Я удаляю nil ценные ключи, создавая подкласс 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
на ваш подкласс. это:
+ (NSValueTransformer *)myDailyDataArrayJSONTransformer {
return [MTLJSONAdapterWithoutNil arrayTransformerWithModelClass:KBDailyData.class];
}
Ответ 3
Overriding - 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 использовался для меня с предыдущей базой кода мантии. Теперь я должен сделать следующее, чтобы продолжить использовать 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
}