iphone - yes - apple touch icon generator




Error con NSJSONSerialization: tipo no válido en JSON write(Menú) (3)

Tengo una aplicación que usa datos centrales con 3 entidades con atributos muy similares. La relación es tal como:

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

Cada entidad tiene una clase asociada: ejemplo

Estoy tratando de generar una 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, obtengo 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 que las clases de entidad (Branch, Menu, etc.) sean compatibles con la serialización JSON?


Eso es porque su clase "Menú" no es serializable en JSON. Básicamente, el lenguaje no sabe cómo debe representarse su objeto en JSON (qué campos incluir, cómo representar referencias a otros objetos ...)

De la referencia de clase NSJSONSerialization

Un objeto que se puede convertir 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 infinito.

Esto significa que el lenguaje sabe cómo serializar diccionarios. Entonces, una forma simple de obtener una representación JSON de su menú es proporcionar una representación del Diccionario de las instancias de su Menú, que luego 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 podrías usarlo así:

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]);

Hay un método de clase isValidJSONObject en NSJSONSerialization que le dice si un objeto puede ser serializado. Como señaló Julien, probablemente tengas que convertir tu objeto en un NSDictionary . NSManagedModel proporciona algunos métodos útiles para obtener todos sus atributos para su entidad. Entonces, podría crear una categoría para NSManagedObject que tenga un método para convertirla a NSDictionary . De esta manera, no tiene que escribir un método toDictionary para cada entidad que quiera convertir a un diccionario.

@implementation NSManagedObject (JSON)

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

Puede usar + isValidJSONObject: método de NSJSONSerialization class. 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];
}




ios5