Origen de iOS Herencia para encapsular NSJSONSerialization

Estoy tratando de encapsular los methods de NSJSONSerialization en una Category en NSObject lugar de repetir la [de] / serialization en todo el código.

.marido

 #import <Foundation/Foundation.h> @interface NSObject (AYIAdditions) + (NSString *)JSONString; + (id)objectFromJSONString; + (id)objectFromJSONData; @end 

Sin embargo, estoy recibiendo el error: No visible @interface para 'NSMutableDictionary' declara el selector 'JSONString'

NSMutableDictionary henetworkinga NSObject y, por lo tanto, debería henetworkingar estos methods de categoría, ¿verdad? ¿Qué me estoy perdiendo?

Como un aparte, está usando las categorías un buen enfoque ( mencionado por Ray Wenderlich ). O debería simplemente crear un object personalizado con algunos methods de class.

En el codigo:

 + (NSString *)JSONString; 

El signo + (Signo más) indica un método de class. Lo más probable es que quieras un método de instancia, así:

 - (NSString *)JSONString; 

Con respecto a la metodología de cómo implementar la serialization: Esto es bastante "aparte". El scope de lo que estás preguntando es muy amplio y has dado muy pocos detalles. Esto es realmente una function del scope de sus necesidades y la cantidad de time / energía que desea invertir, pero para sopesar una opinión:

Una categoría en NSObject parece un poco excesivamente amplia para mí. Creo que es improbable que arroje mejores resultados que, lo que parece una elección más lógica, un protocolo.

Francamente, deseo que NSJSONSerialization haya declarado un protocolo para serializar nuestros propios objects model personalizados, similar a NSCoding , pero no lo hicieron. Eso sigue siendo generalmente la ruta que voy cuando codifico object en JSON . Un protocolo podría parecerse a esto:

 NSString * const MySerializationClassKey = @"MySerializationClassKey"; @protocol MySerializationProtocol <NSObject> @requinetworking -(NSDictionary *)dictionarySerialization; -(id)initFromDictionarySerialization:(NSDictionary *)dictionary; @end 

Y luego sus objects de model personalizados pueden serializar y des-serializar así: (demasiado simplist)

 @interface MyModel() <MySerializationProtocol> @property (strong) NSString *name; @end @implementation MyModel NSString * const MyModelNameKey = @"MyModelNameKey"; @synthesize name = _name; -(NSDictionary *)dictionarySerialization{ // encode object as dictionary return @{MySerializationClassKey: NSStringFromClass(self.class), MyModelNameKey: _name.copy}; } -(id)initFromDictionarySerialization:(NSDictionary *)dictionary{ if ((self = [super init])){ _name = [dictionary objectForKey:MyModelNameKey]; } return self; } @end 

Ahora suponga, para no escribir una biblioteca de serialization completa en una respuesta, que nunca tuvo una NSArray plana de estos objects model. Puede crear una class que utilice NSJSONSerialization en cooperación con estos methods. Para facilitar cada llamada, así:

 @interface MySerializer : NSObject @end @implementation MySerializer +(NSData *)jsonDataFromObject:(NSMutableArray *)array{ for (NSUInteger index = 0; index < array.count; index++) { NSObject *object = [array objectAtIndex:index]; if ([object conformsToProtocol:@protocol(MySerializationProtocol)]){ NSDictionary *dictRep = [(id<MySerializationProtocol>)object dictionarySerialization]; [array replaceObjectAtIndex:index withObject:dictRep]; } } return [NSJSONSerialization dataWithJSONObject:array options:0 error:nil]; } +(NSMutableArray *)objectFromJSONData:(NSData *)data{ NSMutableArray *array = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:nil]; for (NSUInteger index = 0; index < array.count; index++) { NSObject *object = [array objectAtIndex:index]; if ([object isKindOfClass:[NSDictionary class]]){ NSDictionary *dict = (NSDictionary *)object; NSString *className = [dict objectForKey:MySerializationClassKey]; if (className.length > 0) { NSObject *deserialized = [[NSClassFromString(className) alloc] initFromDictionarySerialization:dict]; if (deserialized) [array replaceObjectAtIndex:index withObject:deserialized]; } } } return array; } @end 

Ahora, obviamente, para get cualquier cantidad de código como este, tendrías que atravesar recursivamente los arreglos y dictionarys posibles. Pero esta es mi ruta preferida.

¿Estás seguro de que importaste el encabezado de la categoría?

 #import "NSObject+AYIAdditions.h" 

Si se trata de un enfoque correcto o no es discutible. No creo que sea una buena solución agregar un método a NSObject que no se pueda NSObject en todos los objects (no todos los objects pueden ser serializados por JSON).

Utiliza la class NSJSONSerialization para convertir objects JSON a Foundation y convertir objects Foundation a JSON.

Un object que se puede convertir a JSON debe tener las siguientes properties:

  • El object de nivel superior es un NSArray o NSDictionary.
  • Todos los objects son instancias de NSString, NSNumber, NSArray, NSDictionary o NSNull.
  • Todas las keys del dictionary son instancias de NSString.
  • Los numbers no son NaN o infinito. Se pueden aplicar otras reglas.

Llamar a isValidJSONObject: o intentar una conversión son las forms definitivas de saber si un object dado se puede convertir a datos JSON. fuente: documentos de Apple

por lo que debe definir esa categoría en NSObject. un lugar sensato sería NSArray y NSDictionary.

También crearía una class de serializador, que ofrece un shanetworkingSerializer , que se llamaría desde ambas categorías.


otro enfoque podría ser declarar la categoría en NSObject, pero para pasar un bloque de fallas para el event handlingl caso, los objects no eran serializables.