2012-03-27 19 views
49

Tengo una aplicación que utiliza datos centrales con 3 entidades con atributos muy similares. La relación es tal que:Error con NSJSONSerialization - Tipo no válido en JSON write (Menú)

Branch - >> Menú - >> Categoría - >> FoodItem

Cada entidad tiene una clase asociada: ejemplo

enter image description here

Estoy tratando de generar Representación JSON de los datos en la base de datos sqlite.

//gets a single menu record which has some categories and each of these have some food items 
id obj = [NSArray arrayWithObject:[[DataStore singleton] getHomeMenu]]; 

NSError *err; 
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:obj options:NSJSONWritingPrettyPrinted error:&err]; 

NSLog(@"JSON = %@", [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding]); 

Pero en lugar de JSON, me sale un error SIGABRT.

*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Invalid type in JSON write (Menu)' 

Alguna idea de cómo solucionarlo o cómo hacer las clases de entidad (sucursal, menú, etc.) de serialización JSON compatibles?

Respuesta

81

Eso es porque su clase "Menú" no es serializable en JSON. Bascially el idioma no sabe cómo su objeto debe ser representado en JSON (los campos que desea incluir, cómo representar referencias a otros objetos ...)

Desde el NSJSONSerialization Class Reference

Un objeto que puede ser convertido a JSON debe tener las siguientes propiedades :

  • El objeto de nivel superior es un NSArray o NSDictionary.
  • Todos los objetos son instancias de NSString, NSNumber, NSArray, NSDictionary o NSNull.
  • Todas las claves del diccionario son instancias de NSString.
  • Los números no son NaN o infinitos.

Esto significa que el idioma sabe cómo serializar diccionarios. Por lo que una forma sencilla de obtener una representación JSON de su menú es proporcionar una representación Diccionario de las instancias de menú, que, a continuación, serializar en JSON:

- (NSDictionary *)dictionaryFromMenu:(Menu)menu { 
    [NSDictionary dictionaryWithObjectsAndKeys:[menu.dateUpdated description],@"dateUpdated", 
    menu.categoryId, @"categoryId", 
    //... add all the Menu properties you want to include here 
    nil]; 
} 

Y usted podría usará esta manera:

NSDictionary *menuDictionary = [self dictionaryFromMenu:[[DataStore singleton] getHomeMenu]]; 

NSError *err; 
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:menuDictionary options:NSJSONWritingPrettyPrinted error:&err]; 

NSLog(@"JSON = %@", [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding]); 
+1

gracias esto suena como la manera correcta por delante. Déjame darle un giro. –

+0

Muchas gracias. Funcionó a las mil maravillas. Esta es la solución perfecta que necesitaba. :) –

+1

Atención a todos, sin la pregunta, nunca tendremos esta gran respuesta, entonces, ¿qué hay de votar la pregunta así como la respuesta? –

23

Hay un método de clase isValidJSONObject en NSJSONSerialization que le indica si un objeto se puede serializar. Como señaló Julien, probablemente deba convertir su objeto a NSDictionary. NSManagedModel proporciona algunos métodos útiles para obtener todos sus atributos para su entidad. Por lo tanto, puede crear una categoría para NSManagedObject que tenga un método para convertirla a NSDictionary. De esta forma, no tiene que escribir un método toDictionary para cada entidad que desee convertir a un diccionario.

@implementation NSManagedObject (JSON) 

- (NSDictionary *)toDictionary 
{ 
    NSArray *attributes = [[self.entity attributesByName] allKeys]; 
    NSDictionary *dict = [self dictionaryWithValuesForKeys:attributes]; 
    return dict; 
} 
+0

esta es una buena idea. gracias –

+0

Esto me ayudó mucho. ¡Gracias! – Fogh

1

Puede utilizar + isValidJSONObject: método de clase NSJSONSerialization. Si no es válido, puede usar - initWithData: encoding: method of NSString.

- (NSString *)prettyPrintedJson:(id)jsonObject 
{ 
    NSData *jsonData; 

    if ([NSJSONSerialization isValidJSONObject:jsonObject]) { 
     NSError *error; 
     jsonData = [NSJSONSerialization dataWithJSONObject:jsonObject 
                  options:NSJSONWritingPrettyPrinted 
                  error:&error]; 

     if (error) { 
      return nil; 
     } 
    } else { 
     jsonData = jsonObject; 
    } 

    return [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding]; 
} 
0

que tenía la llave de conmutación con el valor: @ {valor: @ "clave"} Debe ser @ {@ "clave": valor}

Cuestiones relacionadas