web-dev-qa-db-fra.com

Erreur avec NSJSONSerialization - Type non valide en écriture JSON (Menu)

J'ai une application utilisant des données de base avec 3 entités avec des attributs très similaires. La relation est telle que:

Succursale - >> Menu - >> Catégorie - >> FoodItem 

Chaque entité a une classe associée: exemple

enter image description here

J'essaie de générer une représentation JSON des données dans la base de données 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]);

Mais au lieu de JSON, je reçois une erreur SIGABRT.

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

Des idées pour résoudre ce problème ou pour rendre les classes d'entités (branche, menu, etc.) compatibles avec la sérialisation JSON? 

50
Vaibhav Garg

En effet, votre classe "Menu" n'est pas sérialisable en JSON. En gros, le langage ne sait pas comment votre objet doit être représenté en JSON (quels champs inclure, comment représenter les références à d'autres objets ...)

Depuis la référence de la classe NSJSONSerialization

Un objet pouvant être converti en JSON doit avoir le suivant Propriétés:

  • L'objet de niveau supérieur est un NSArray ou NSDictionary. 
  • Tous les objets sont des instances de NSString, NSNumber, NSArray, NSDictionary ou NSNull.
  • Toutes les clés de dictionnaire sont des instances de NSString. 
  • Les nombres ne sont ni NaN ni l'infini.

Cela signifie que la langue sait sérialiser les dictionnaires. Ainsi, un moyen simple d'obtenir une représentation JSON à partir de votre menu consiste à fournir une représentation de dictionnaire de vos instances de menu, que vous allez ensuite sérialiser 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];
}

Et vous pourriez l'utiliser comme ceci:

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

Il existe une méthode de classe isValidJSONObject sur NSJSONSerialization qui vous indique si un objet peut être sérialisé. Comme Julien l'a souligné, vous devez probablement convertir votre objet en un NSDictionary. NSManagedModel fournit des méthodes pratiques pour obtenir tous vos attributs pour votre entité. Vous pouvez donc créer une catégorie pour NSManagedObject avec une méthode pour la convertir en NSDictionary. Ainsi, vous n'avez pas besoin d'écrire une méthode toDictionary pour chaque entité que vous souhaitez convertir en dictionnaire.

@implementation NSManagedObject (JSON)

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

Vous pouvez utiliser la méthode + isValidJSONObject: de la classe NSJSONSerialization. Si ce n'est pas valide, vous pouvez utiliser - 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];
}
1
Fatih Aksu

La clé a été commutée avec la valeur: @ {valeur: @ "clé"} Ce devrait être @ {@ "clé": valeur}

0
jonypz