web-dev-qa-db-fra.com

sérialisation JSON iOS pour les classes NSObject

Je voudrais JSON-sérialiser mes propres classes personnalisées. Je travaille dans Objective-C/iOS5. J'aimerais que les tâches suivantes soient effectuées:

Person* person = [self getPerson ]; // Any custom object, NOT based on NSDictionary
NSString* jsonRepresentation = [JsonWriter stringWithObject:person ];
Person* clone = [JsonReader objectFromJson: jsonRepresentation withClass:[Person Class]];

Il semble que NSJSONSerialization (et plusieurs autres bibliothèques) exigent que la classe 'personne' soit basée sur NSDictionary, etc. Je veux quelque chose qui sérialisera tout objet personnalisé que je tiens à définir (dans des limites raisonnables).

Imaginons que Person.h ressemble à ceci:

#import <Foundation/Foundation.h>
@interface Person : NSObject 
@property NSString* firstname;
@property NSString* surname;
@end

Je voudrais que le JSON généré pour une instance ressemble à ce qui suit:

{"firstname":"Jenson","surname":"Button"}

Mon application utilise ARC. J'ai besoin de quelque chose qui sérialisera et désérialisera en utilisant des objets.

Merci beaucoup.

18
Journeyman

C'est une question délicate car les seules données que vous pouvez mettre dans JSON sont des objets simples et droits (pensez à NSString, NSArray, NSNumber…) mais pas des classes personnalisées ou des types scalaires. Pourquoi? Sans construire toutes sortes d'instructions conditionnelles pour englober tous ces types de données dans ces types d'objets, une solution ressemblerait à ceci:

//at the top…
#import <objC/runtime.h>

    NSMutableDictionary *muteDictionary = [NSMutableDictionary dictionary];

    id YourClass = objc_getClass("YOURCLASSNAME");
    unsigned int outCount, i;
    objc_property_t *properties = class_copyPropertyList(YourClass, &outCount);
    for (i = 0; i < outCount; i++) {
        objc_property_t property = properties[i];
        NSString *propertyName = [NSString stringWithCString:property_getName(property) encoding:NSUTF8StringEncoding];
        SEL propertySelector = NSSelectorFromString(propertyName);
        if ([classInstance respondsToSelector:propertySelector]) {
            [muteDictionary setValue:[classInstance performSelector:propertySelector] forKey:propertyName];
        }
    }
    NSError *jsonError = nil;
    NSData *jsonData = [NSJSONSerialization dataWithJSONObject:muteDictionary options:0 error:&jsonError];

C'est délicat, mais à cause de ce que j'ai déjà dit. Si vous avez des types scalaires ou des objets personnalisés, tout s’effondre. S'il est vraiment essentiel de mettre en place une solution de ce type, je suggérerais d'investir du temps et de consulter les liens de Ricard qui vous permettent de voir les types de propriétés susceptibles d'aider les instructions conditionnelles nécessaires pour intégrer les valeurs dans des objets compatibles NSDictionary. 

23

Maintenant, vous pouvez résoudre ce problème facilement en utilisant JSONModel . JSONModel est une bibliothèque qui sérialise/désérialise de manière générique votre objet en fonction de Class. Vous pouvez même utiliser des propriétés non-nsobject comme int, short et float. Il peut également prendre en charge des fichiers JSON imbriqués complexes.

Exemple de désérialisation . En vous référant à votre exemple, dans le fichier d'en-tête:

#import "JSONModel.h"

@interface Person : JSONModel 
@property (nonatomic, strong) NSString* firstname;
@property (nonatomic, strong) NSString* surname;
@end

dans le fichier d'implémentation:

#import "JSONModelLib.h"
#import "yourPersonClass.h"

NSString *responseJSON = /*from somewhere*/;
Person *person = [[Person alloc] initWithString:responseJSON error:&err];
if (!err)
{
   NSLog(@"%@  %@", person.firstname, person.surname):
}

Exemple de sérialisation . En fichier d'implémentation:

#import "JSONModelLib.h"
#import "yourPersonClass.h"

Person *person = [[Person alloc] init];
person.firstname = @"Jenson";
person.surname = @"Uee";

NSLog(@"%@", [person toJSONString]);
16
X Sham

peut-être que cela peut aider JLObjectStrip

c'est la même chose que ce que jacob a dit mais cela revient même à la propriété de la classe. cela vous donnera dictionnaire/tableau puis utilisez simplement sbjson/jsonkit ou ce que vous préférez pour construire votre chaîne json.

1
Joshua

Ce que je fais pour mes objets, c’est que j’ai une méthode appelée "toDict" qui renvoie un nsdictionary. DANS cette méthode, je mets par exemple tous les attributs nécessaires

[user setObject:self.first_name forKey:@"first_name"];
[user setObject:self.last_name forKey:@"last_name"];
[user setObject:self.email forKey:@"email"];
0
Travis Delly

Essayez celui-ci BWJSONMatcher

C'est très simple et pratique.

...
NSString *jsonString = @"{your-json-string}";
YourValueObject *dataModel = [YourValueObject fromJSONString:jsonString];

NSDictionary *jsonObject = @{your-json-object};
YourValueObject *dataModel = [YourValueObject fromJSONObject:jsonObject];
...
YourValueObject *dataModel = instance-of-your-value-object;
NSString *jsonString = [dataModel toJSONString];
NSDictionary *jsonObject = [dataModel toJSONObject];
...
0
Burrows Wang