Obj-C简单的方法来从NSObject的属性转换为NSDictionary?

我遇到了一些我最终想到的东西,但是认为可能有更高效的方法来实现它。

我有一个对象(一个采用了MKAnnotation协议的NSObject),它具有许多属性(标题,副标题,纬度,经度,信息等)。 我需要能够将这个对象传递给另一个对象,它想使用objectForKey方法从它提取信息作为一个NSDictionary(因为这是从另一个视图控制器得到的)。

我最终做的是创build一个新的NSMutableDictionary,并使用setObject:forKey来传输每一个重要的信息,然后我只是传递新创build的字典。

有没有更简单的方法来做到这一点?

以下是相关的代码:

// sender contains a custom map annotation that has extra properties... - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { if ([[segue identifier] isEqualToString:@"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; } } 

提前感谢你的集体智慧。


以下是我想到的,感谢下面的人们…

 - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { if ([[segue identifier] isEqualToString:@"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; } 

}

而更简单的修复,如下所示…

使用valueForKey而不是object的key来检索信息。


如果这些属性与用于访问字典的键名称相同,则可以使用KVC并使用valueForKey:而不是objectForKey

例如给这个字典

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

和这个对象

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

如果我有可以打电话的字典或MyAnnotation的实例,那也没有关系

 [annotation valueForKey:@"title"]; 

很明显,这也是另一种方式

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

当然可以! 使用objc运行时和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++) { NSString *key = [NSString stringWithUTF8String:property_getName(properties[i])]; [dict setObject:[obj valueForKey:key] forKey:key]; } free(properties); return [NSDictionary dictionaryWithDictionary:dict]; } @end 

你会这样使用:

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

这是一个旧的post,理查德J.罗斯三世的答案是非常有用的,但在自定义对象的情况下(一个自定义类中有另一个自定义对象)。 然而,有时属性是其他对象等,使序列化有点复杂。

 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; 

为了将这些types的对象(多个自定义对象)转换成字典,我不得不稍微修改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++) { NSString *key = [NSString stringWithUTF8String:property_getName(properties[i])]; Class classObject = NSClassFromString([key capitalizedString]); 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.罗斯的方法,这一个与自定义对象的NSArray工作。

 +(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])]; Class classObject = NSClassFromString([key capitalizedString]); 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]; } 

有太多的解决scheme,没有为我工作,因为我有一个复杂的嵌套对象结构。 这个解决scheme从理查德和达米安(Richard)和达米安(Damien)那里得到了一些东西,但即将来临的是,达米安的解决scheme将命名键与类名称联系起

这是标题

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

这是.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++) { NSString *key = [NSString stringWithUTF8String: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:[NSString class]]) { dict[key] = object; } else if ([object isKindOfClass:[NSDate class]]) { dict[key] = [[NSDictionary getReverseDateFormatter] stringFromDate:(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 

您也可以使用GitHub上的NSObject+APObjectMapping类别: https : //github.com/aperechnev/APObjectMapping

这是一个简单的退出。 只需描述你的类中的映射规则:

 #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 

然后你可以很容易地将你的对象映射到字典:

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

你也可以从字典中parsing你的对象:

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