Obj-C méthode facile à convertir de NSObject avec des propriétés à NSDictionary?

J'ai croisé quelque chose que j'ai finalement compris, mais je pense qu'il y a probablement un moyen beaucoup plus efficace de l'accomplir.

J'avais un object (un NSObject qui a adopté le protocole MKAnnotation) qui avait un certain nombre de propriétés (titre, sous-titre, latitude, longitude, info, etc.). Je devais être capable de passer cet object à un autre object, qui voulait en extraire des informations en utilisant les methods objectForKey, comme un NSDictionary (parce que c'est ce qu'il obtenait d'un autre controller de vue).

Ce que j'ai fini par faire était de créer un nouveau NSMutableDictionary et d'utiliser setObject: forKey pour transférer chaque morceau d'information vitale, et je viens de transmettre le nouveau dictionary.

Y avait-il un moyen plus facile de faire cela?

Voici le code pertinent:

// sender contains a custom map annotation that has extra properties... - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { if ([[segue identifier] isEqualToSsortingng:@"showDetailFromMap"]) { DetailViewController *dest =[segue destinationViewController]; //make a dictionary from annotaion to pass info NSMutableDictionary *myValues =[[NSMutableDictionary alloc] init]; //fill with the relevant info [myValues setObject:[sender title] forKey:@"title"] ; [myValues setObject:[sender subtitle] forKey:@"subtitle"]; [myValues setObject:[sender info] forKey:@"info"]; [myValues setObject:[sender pic] forKey:@"pic"]; [myValues setObject:[sender latitude] forKey:@"latitude"]; [myValues setObject:[sender longitude] forKey:@"longitude"]; //pass values dest.curLoc = myValues; } } 

Merci d'avance pour votre sagesse collective.


Voici ce que j'ai trouvé, merci aux gens, ci-dessous …

 - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { if ([[segue identifier] isEqualToSsortingng:@"showDetailFromMap"]) { DetailViewController *dest =[segue destinationViewController]; NSArray *myKeys = [NSArray arrayWithObjects: @"title",@"subtitle",@"info",@"pic",@"latitude",@"longitude", nil]; //make a dictionary from annotaion to pass info NSDictionary *myValues =[sender dictionaryWithValuesForKeys:myKeys]; //pass values dest.curLoc = myValues; } 

}

Et une solution encore plus simple, comme on le voit ci-dessous …

Utiliser valueForKey au lieu de object pour la key pour récupérer l'information.


Si les propriétés avaient les mêmes noms que les keys utilisées pour accéder au dictionary, vous auriez pu utiliser KVC et valueForKey: au lieu de objectForKey .

Par exemple vu ce dictionary

 NSDictionary *annotation = [[NSDictionary alloc] initWithObjectsAndKeys: @"A title", @"title", nil]; 

et cet object

 @interface MyAnnotation : NSObject @property (nonatomic, copy) NSSsortingng *title; @end 

cela n'aurait pas d'importance si j'avais une instance du dictionary ou MyAnnotation je pourrais appeler

 [annotation valueForKey:@"title"]; 

Évidemment, cela fonctionne aussi dans l'autre sens, par exemple

 [annotation setValue:@"A title" forKey:@"title"]; 

Chose sûre! Utilisez l'objc-runtime et le KVC!

 #import <objc/runtime.h> @interface NSDictionary(dictionaryWithObject) +(NSDictionary *) dictionaryWithPropertiesOfObject:(id) obj; @end @implementation NSDictionary(dictionaryWithObject) +(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++) { NSSsortingng *key = [NSSsortingng ssortingngWithUTF8Ssortingng:property_getName(properties[i])]; [dict setObject:[obj valueForKey:key] forKey:key]; } free(properties); return [NSDictionary dictionaryWithDictionary:dict]; } @end 

Et vous utiliseriez comme ceci:

 MyObj *obj = [MyObj new]; NSDictionary *dict = [NSDictionary dictionaryWithPropertiesOfObject:obj]; NSLog(@"%@", dict); 

C'est un ancien article et la réponse de Richard J. Ross III est vraiment utile, mais dans le cas d'objects personnalisés (une class personnalisée a un autre object personnalisé). Cependant, les propriétés sont parfois d'autres objects et ainsi de suite, rendant la serialization un peu compliquée.

 Details * details = [[Details alloc] init]; details.tomato = @"Tomato 1"; details.potato = @"Potato 1"; details.mangoCount = [NSNumber numberWithInt:12]; Person * person = [[Person alloc]init]; person.name = @"HS"; person.age = @"126 Years"; person.gender = @"?"; person.details = details; 

Pour convertir ces types d'objects (plusieurs objects personnalisés) en dictionary, j'ai dû modifier un peu la réponse de Richard J. Ross III.

 +(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++) { NSSsortingng *key = [NSSsortingng ssortingngWithUTF8Ssortingng:property_getName(properties[i])]; Class classObject = NSClassFromSsortingng([key capitalizedSsortingng]); if (classObject) { id subObj = [self dictionaryWithPropertiesOfObject:[obj valueForKey:key]]; [dict setObject:subObj forKey:key]; } else { id value = [obj valueForKey:key]; if(value) [dict setObject:value forKey:key]; } } free(properties); return [NSDictionary dictionaryWithDictionary:dict]; } 

J'espère que ça va aider quelqu'un. Le crédit complet va à Richard J. Ross III.

Pour compléter la méthode de Richard J. Ross, celle-ci fonctionne avec NSArray d'object personnalisé.

 +(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++) { NSSsortingng *key = [NSSsortingng ssortingngWithUTF8Ssortingng:property_getName(properties[i])]; Class classObject = NSClassFromSsortingng([key capitalizedSsortingng]); id object = [obj valueForKey:key]; if (classObject) { id subObj = [self dictionaryWithPropertiesOfObject:object]; [dict setObject:subObj forKey:key]; } else if([object isKindOfClass:[NSArray class]]) { NSMutableArray *subObj = [NSMutableArray array]; for (id o in object) { [subObj addObject:[self dictionaryWithPropertiesOfObject:o] ]; } [dict setObject:subObj forKey:key]; } else { if(object) [dict setObject:object forKey:key]; } } free(properties); return [NSDictionary dictionaryWithDictionary:dict]; } 

Il y a tellement de solutions et rien n'a fonctionné pour moi car j'avais une structure complexe nestede. Cette solution prend des choses de Richard et Damien mais improvise car la solution de Damien est liée à la désignation des keys en tant que noms de class.

Voici l'en-tête

 @interface NSDictionary (PropertiesOfObject) +(NSDictionary *) dictionaryWithPropertiesOfObject:(id)obj; @end 

Voici le file .m

 @implementation NSDictionary (PropertiesOfObject) static NSDateFormatter *reverseFormatter; + (NSDateFormatter *)getReverseDateFormatter { if (!reverseFormatter) { NSLocale *locale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"]; reverseFormatter = [[NSDateFormatter alloc] init]; [reverseFormatter setDateFormat:@"yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"]; [reverseFormatter setLocale:locale]; } return reverseFormatter; } + (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++) { NSSsortingng *key = [NSSsortingng ssortingngWithUTF8Ssortingng:property_getName(properties[i])]; id object = [obj valueForKey:key]; if (object) { if ([object isKindOfClass:[NSArray class]]) { NSMutableArray *subObj = [NSMutableArray array]; for (id o in object) { [subObj addObject:[self dictionaryWithPropertiesOfObject:o]]; } dict[key] = subObj; } else if ([object isKindOfClass:[NSSsortingng class]]) { dict[key] = object; } else if ([object isKindOfClass:[NSDate class]]) { dict[key] = [[NSDictionary getReverseDateFormatter] ssortingngFromDate:(NSDate *) object]; } else if ([object isKindOfClass:[NSNumber class]]) { dict[key] = object; } else if ([[object class] isSubclassOfClass:[NSObject class]]) { dict[key] = [self dictionaryWithPropertiesOfObject:object]; } } } return dict; } @end 

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

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

 #import <Foundation/Foundation.h> #import "NSObject+APObjectMapping.h" @interface MyCustomClass : NSObject @property (nonatomic, strong) NSNumber * someNumber; @property (nonatomic, strong) NSSsortingng * someSsortingng; @end @implementation MyCustomClass + (NSMutableDictionary *)objectMapping { NSMutableDictionary * mapping = [super objectMapping]; if (mapping) { NSDictionary * objectMapping = @{ @"someNumber": @"some_number", @"someSsortingng": @"some_ssortingng" }; } return mapping } @end 

Et puis vous pouvez facilement mapper votre object au dictionary:

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

Vous pouvez également parsingr votre object à partir du dictionary:

 NSDictionary * myDict = @{ @"some_number": @123, @"some_ssortingng": @"some ssortingng" }; MyCustomClass * myObj = [[MyCustomClass alloc] initWithDictionary:myDict];