web-dev-qa-db-fra.com

Conversion de NSObject en NSDictionary

Bonjour je suis une classe de type NSObject:

ProductDetails *details = [[ProductDetails alloc] init];
details.name = @"Soap1";
details.color = @"Red";
details.quantity = 4;

Je souhaite transmettre l'objet "détails" à un dictionnaire. 

J'ai fait, 

NSDictionary *dict = [NSDictionary dictionaryWithObject:details forKey:@"details"];

Je passe ce dict à une autre méthode qui vérifie JSONSerialization:

if(![NSJSONSerialization isValidJSONObject:dict])

Et je reçois un crash sur ce chèque. Est-ce que je fais quelque chose de mal ici? Je sais que les détails que je reçois sont un objet JSON et je l'assigne aux propriétés de ma classe ProductDetails.

Aidez-moi, s'il vous plaît. Je suis un noob en Objective-C.

J'ai maintenant essayé:

NSError* error;
NSDictionary* json = [NSJSONSerialization JSONObjectWithData:(NSData*)details options:kNilOptions error:&error];

Tout ce dont j'ai besoin ici est un moyen facile de convertir les détails en NSData. 

J'ai remarqué que j'ai un tableau à l'intérieur de mon objet peut-être pourquoi tous les moyens que j'ai essayés est de lancer une exception. Cependant, depuis que cette question est devenue trop grosse, j'ai commencé un autre fil de question où j'ai affiché les données que je reçois dans l'objet - https://stackoverflow.com/questions/19081104/convert-nsobject-to -nsdictionary

9
tech_human
NSDictionary *details = {@"name":product.name,@"color":product.color,@"quantity":@(product.quantity)};

NSError *error; 
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:details 
                                                   options:NSJSONWritingPrettyPrinted // Pass 0 if you don't care about the readability of the generated string
                                                     error:&error];

if (! jsonData) {
    NSLog(@"Got an error: %@", error);
} else {
    NSString *jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
}

Source de la deuxième partie: Générer une chaîne JSON à partir de NSDictionary sous iOS

13
mmackh

C'est peut-être le moyen le plus simple d'y parvenir. Importez #import <objc/runtime.h> dans votre fichier de classe.

#import <objc/runtime.h>

ProductDetails *details = [[ProductDetails alloc] init];
details.name = @"Soap1";
details.color = @"Red";
details.quantity = 4;
NSDictionary *dict = [self dictionaryWithPropertiesOfObject: details];
NSLog(@"%@", dict);

//Add this utility method in your class.
- (NSDictionary *) dictionaryWithPropertiesOfObject:(id)obj
{
    NSMutableDictionary *dict = [NSMutableDictionary dictionary];

    unsigned count;
    objc_property_t *properties = class_copyPropertyList([obj class], &count);

    for (int i = 0; i < count; i++) {
        NSString *key = [NSString stringWithUTF8String:property_getName(properties[i])];
        [dict setObject:[obj valueForKey:key] forKey:key];
    }

    free(properties);

    return [NSDictionary dictionaryWithDictionary:dict];
}
15
thatzprem

Dans le fichier .h

#import <Foundation/Foundation.h>

@interface ContactDetail : NSObject
@property (nonatomic) NSString *firstName;
@property (nonatomic) NSString *lastName;
@property (nonatomic) NSString *fullName;
@property (nonatomic) NSMutableArray *mobileNumbers;
@property (nonatomic) NSMutableArray *Emails;
@property (assign) bool Isopen;
@property (assign) bool IsChecked;
-(NSDictionary *)dictionary;
@end

dans le fichier .m

#import "ContactDetail.h"
#import <objc/runtime.h>

@implementation ContactDetail

@synthesize firstName;
@synthesize lastName;
@synthesize fullName;
@synthesize mobileNumbers;
@synthesize Emails;

@synthesize IsChecked,Isopen;

//-(NSDictionary *)dictionary {
//    return [NSDictionary dictionaryWithObjectsAndKeys:self.fullName,@"fullname",self.mobileNumbers,@"mobileNumbers",self.Emails,@"emails", nil];
//}

- (NSDictionary *)dictionary {
    unsigned int count = 0;
    NSMutableDictionary *dictionary = [NSMutableDictionary new];
    objc_property_t *properties = class_copyPropertyList([self class], &count);

    for (int i = 0; i < count; i++) {

        NSString *key = [NSString stringWithUTF8String:property_getName(properties[i])];
        id value = [self valueForKey:key];

        if (value == nil) {
            // nothing todo
        }
        else if ([value isKindOfClass:[NSNumber class]]
                 || [value isKindOfClass:[NSString class]]
                 || [value isKindOfClass:[NSDictionary class]] || [value isKindOfClass:[NSMutableArray class]]) {
            // TODO: extend to other types
            [dictionary setObject:value forKey:key];
        }
        else if ([value isKindOfClass:[NSObject class]]) {
            [dictionary setObject:[value dictionary] forKey:key];
        }
        else {
            NSLog(@"Invalid type for %@ (%@)", NSStringFromClass([self class]), key);
        }
    }
    free(properties);
    return dictionary;
}
@end

en cas de blocage, vous vérifiez la propriété (NSMutableArray, NSString, etc.) dans sinon si condition à l'intérieur de pour .

Dans votre contrôleur, dans n'importe quel fonction ...

-(void)addItemViewController:(ConatctViewController *)controller didFinishEnteringItem:(NSMutableArray *)SelectedContact
{
    NSLog(@"%@",SelectedContact);

    NSMutableArray *myData = [[NSMutableArray alloc] init];
    for (ContactDetail *cont in SelectedContact) {
        [myData addObject:[cont dictionary]];
    }

    NSError *error = nil;
    NSData *jsonData = [NSJSONSerialization dataWithJSONObject:myData options:NSJSONWritingPrettyPrinted error:&error];
    if ([jsonData length] > 0 &&
        error == nil){
//        NSLog(@"Successfully serialized the dictionary into data = %@", jsonData);
        NSString *jsonString = [[NSString alloc] initWithData:jsonData
                                                     encoding:NSUTF8StringEncoding];
        NSLog(@"JSON String = %@", jsonString);
    }
    else if ([jsonData length] == 0 &&
             error == nil){
        NSLog(@"No data was returned after serialization.");
    }
    else if (error != nil){
        NSLog(@"An error happened = %@", error);
    }
}
3
Jaleel Nazir

Comme mmackh a dit, vous voulez définir une méthode personnalisée pour votre objet ProductDetails qui renverra une simple NSDictionary de valeurs, par exemple:

@implementation ProductDetails

- (id)jsonObject
{
    return @{@"name"     : self.name,
             @"color"    : self.color,
             @"quantity" : @(self.quantity)};
}

...

Supposons que nous ayons ajouté la propriété manufacturer à notre ProductDetails, qui faisait référence à une classe ManufacturerDetails. Nous écririons simplement une jsonObject pour cette classe aussi:

@implementation ManufacturerDetails

- (id)jsonObject
{
    return @{@"name"     : self.name,
             @"address1" : self.address1,
             @"address2" : self.address2,
             @"city"     : self.city,
             ...
             @"phone"    : self.phone};
}

...

Et puis changez la jsonObject pour ProductDetails pour l’employer, par exemple:

@implementation ProductDetails

- (id)jsonObject
{
    return @{@"name"         : self.name,
             @"color"        : self.color,
             @"quantity"     : @(self.quantity),
             @"manufacturer" : [self.manufacturer jsonObject]};
}

...

Si vous avez des objets de collection potentiellement imbriqués (tableaux et/ou dictionnaires) avec des objets personnalisés que vous souhaitez encoder, vous pouvez également écrire une méthode jsonObject pour chacun d'entre eux:

@interface NSDictionary (JsonObject)

- (id)jsonObject;

@end

@implementation NSDictionary (JsonObject)

- (id)jsonObject
{
    NSMutableDictionary *dictionary = [NSMutableDictionary dictionary];

    [self enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
        if ([obj respondsToSelector:@selector(jsonObject)])
            [dictionary setObject:[obj jsonObject] forKey:key];
        else
            [dictionary setObject:obj forKey:key];
    }];

    return [NSDictionary dictionaryWithDictionary:dictionary];
}

@end

@interface NSArray (JsonObject)

- (id)jsonObject;

@end

@implementation NSArray (JsonObject)

- (id)jsonObject
{
    NSMutableArray *array = [NSMutableArray array];

    [self enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
        if ([obj respondsToSelector:@selector(jsonObject)])
            [array addObject:[obj jsonObject]];
        else
            [array addObject:obj];
    }];

    return [NSArray arrayWithArray:array];
}

@end

Si vous faites quelque chose comme ça, vous pouvez maintenant convertir des tableaux ou des dictionnaires de votre objet d'objet personnalisé en quelque chose qui peut être utilisé pour générer du JSON:

NSArray *products = @[[[Product alloc] initWithName:@"Prius"  color:@"Green" quantity:3],
                      [[Product alloc] initWithName:@"Accord" color:@"Black" quantity:1],
                      [[Product alloc] initWithName:@"Civic"  color:@"Blue"  quantity:2]];

id productsJsonObject = [products jsonObject];

NSError *error = nil;
NSData *data = [NSJSONSerialization dataWithJSONObject:productsJsonObject options:0 error:&error];

Si vous essayez simplement de sauvegarder ces objets dans un fichier, je suggérerais NSKeyedArchiver et NSKeyedUnarchiver. Toutefois, si vous devez générer des objets JSON pour vos propres classes privées, vous pouvez effectuer les opérations suivantes.

2
Rob

Vous pouvez convertir un objet (par exemple, modelObject) en dictionnaire au moment de l'exécution à l'aide de objc/runtime.h class, mais présente certaines limitations et correspond à non recommandé .

Compte tenu deMVC, la logique de mappage doit être implémentée dans la classe Model.

@interface ModelObject : NSObject
@property (nonatomic) NSString *p1;
@property (nonatomic) NSString *p2;
-(NSDictionary *)dictionary;
@end


#import "ModelObject.h"

@implementation ModelObject
-(NSDictionary *)dictionary
{
    NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];

    [dict setValue:self.p1 forKey:@"p1"];// you can give different key name here if you want 
    [dict setValue:self.p2 forKey:@"p2" ];

    return dict;
}
@end

Les usages:

NSDictionary *modelObjDict = [modelObj dictionary];
0
PANKAJ VERMA

Essaye ça:

#import <objc/runtime.h>

+ (NSDictionary *)dictionaryWithPropertiesOfObject:(id)obj {
    NSMutableDictionary *dict = [NSMutableDictionary dictionary];

    unsigned count;
    objc_property_t *properties = class_copyPropertyList([obj class], &count);

    for (int i = 0; i < count; i++) {
        NSString *key = [NSString stringWithUTF8String:property_getName(properties[i])];
        [dict setObject:[obj valueForKey:key] ? [obj valueForKey:key] : @"" forKey:key];
    }

    free(properties);

    return [NSDictionary dictionaryWithDictionary:dict];
}
0
刘俊利

Vous pouvez aussi utiliser la catégorie NSObject+APObjectMapping qui est disponible sur GitHub: https://github.com/aperechnev/APObjectMapping

C'est un facile quitter. Décrivez simplement les règles de mappage dans votre classe:

#import <Foundation/Foundation.h>
#import "NSObject+APObjectMapping.h"

@interface MyCustomClass : NSObject
@property (nonatomic, strong) NSNumber * someNumber;
@property (nonatomic, strong) NSString * someString;
@end

@implementation MyCustomClass
+ (NSMutableDictionary *)objectMapping {
  NSMutableDictionary * mapping = [super objectMapping];
  if (mapping) {
    NSDictionary * objectMapping = @{ @"someNumber": @"some_number",
                                      @"someString": @"some_string" };
  }
  return mapping
}
@end

Et ensuite, vous pouvez facilement mapper votre objet sur le dictionnaire:

MyCustomClass * myObj = [[MyCustomClass alloc] init];
myObj.someNumber = @1;
myObj.someString = @"some string";
NSDictionary * myDict = [myObj mapToDictionary];

Aussi, vous pouvez analyser votre objet à partir du dictionnaire:

NSDictionary * myDict = @{ @"some_number": @123,
                           @"some_string": @"some string" };
MyCustomClass * myObj = [[MyCustomClass alloc] initWithDictionary:myDict];
0
Alexander Perechnev

Le moyen idéal pour cela consiste à utiliser une bibliothèque pour la sérialisation/désérialisation De nombreuses bibliothèques sont disponibles, mais l'une d'entre elles est JagPropertyConverter https://github.com/ jagill/JAGPropertyConverter

il peut convertir votre objet personnalisé en NSDictionary et vice versa
Même s'il prend en charge la conversion de dictionnaire ou de tableau ou de tout objet personnalisé dans votre objet (par exemple, Composition)

JAGPropertyConverter *converter = [[JAGPropertyConverter alloc]init];
converter.classesToConvert = [NSSet setWithObjects:[ProductDetails class], nil];


//For Object to Dictionary 
NSDictionary *dictDetail = [converter convertToDictionary:detail];
NSDictionary* json = [NSJSONSerialization JSONObjectWithData:dictDetail options:NSJSONWritingPrettyPrinted error:&error];
0
M.Shuaib Imran

Essayez d'utiliser 

NSDictionary *dict = [details valuesForAttributes:@[@"name", @"color"]];

Et comparez ce que contient le dictionnaire. Ensuite, essayez de le convertir en JSON. Et regardez la spécification JSON - quels types de données peuvent être insérés dans un fichier encodé JSON?

0
Wain