ios - ¿Cómo omitir los valores nulos en el diccionario JSON usando Mantle?
github-mantle (4)
Tengo MyModel heredado de MTLModel (usando el pod GitHub Mantle). 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
Ahora quiero enviar el JSON al backend usando AFNetworking. Antes de eso, convierto la instancia del modelo a un JSON NSDictionary para usar como parámetros / carga útil del cuerpo dentro de mi solicitud.
NSDictionary *JSON = [MTLJSONAdapter JSONDictionaryFromModel:myModel];
Pero este JSON consta de "" cadenas extrañas para las propiedades de mi modelo que son nulas. Lo que en cambio quiero es que Mantle omita estos pares clave / valor y solo escupa un JSON con solo las propiedades que no son nulas o NSNull.null, lo que sea.
Anulación: el diccionario de valores no me dio el comportamiento esperado
Así que creé un método para la clase Base 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];
}
El EDIT # 2 solía trabajar para mí con la base de código Mantle anterior. Ahora tengo que hacer lo siguiente para continuar usando EDIT # 2:
En el archivo MTLJSONAdapter.m, reemplace esta línea:
NSDictionary *dictionaryValue = [model.dictionaryValue dictionaryWithValuesForKeys:propertyKeysToSerialize.allObjects];
con
NSDictionary *dictionaryValue = model.dictionaryValue;
La anterior es mi actual solución para conseguir
{ }
en lugar de
{
"AddressLine2" : null,
"City" : null,
"ZipCode" : null,
"State" : null,
"AddressLine1" : null
}
Este es un problema común con Mantle y se denomina asignación JSON implícita .
MTLJSONAdapter
lee todas las propiedades de un modelo para crear una cadena JSON que reemplaza opcionalmente los nombres de propiedad con los que se dan en +JSONKeyPathsByPropertyKey
.
Si desea que algunas propiedades sean excluidas de la representación JSON de su modelo, NSNull.null
a NSNull.null
en su +JSONKeyPathsByPropertyKey
:
+ (NSDictionary *)JSONKeyPathsByPropertyKey {
return @{
@"UUID": @"id",
@"someProp": @"some_prop",
@"anotherProp": @"another",
@"myInternalProperty": NSNull.null,
@"myAnotherInternalProperty": NSNull.null,
};
}
El mapeo JSON implícito se ha convertido últimamente en un problema notable, una solución para la cual se está discutiendo actualmente en el repositorio de Mantle en GitHub.
Vea los temas #137 , #138 , #143 y la discusión actual en #149 .
EDIT: claramente entendí mal la pregunta, pero ahora, cuando supongo que la entiendo correctamente, la respuesta es simple.
MTLJSONAdapter
genera los datos JSON usando la propiedad dictionaryValue
MTLModel
. Si desea excluir una propiedad del propio JSON, puede sobrescribir ese método en su 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: verifique el código * para eliminar todos los valores que son 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.
Quito las claves de valor nulo al crear una subclase MTLJSONAdapter y al reemplazar -serializablePropertyKeys:forModel:
method.
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
Y usa esto para crear el diccionario JSON en su lugar. Me gusta esto:
NSDictionary *JSONDictionary = [MTLJSONAdapterWithoutNil JSONDictionaryFromModel:collection error:nil];
NOTA: si está anulando los métodos de NSValueTransformer
para las propiedades de matriz o diccionario, también debe cambiar la clase MTLJSONAdapter
a su subclase. Me gusta esto:
+ (NSValueTransformer *)myDailyDataArrayJSONTransformer {
return [MTLJSONAdapterWithoutNil arrayTransformerWithModelClass:KBDailyData.class];
}