簡體   English   中英

從帶有屬性的NSObject轉換為NSDictionary的Obj-C簡單方法?

[英]Obj-C easy method to convert from NSObject with properties to NSDictionary?

我遇到了一些我最終想到的東西,但認為可能有一種更有效的方法來實現它。

我有一個對象(一個采用MKAnnotation協議的NSObject),它有許多屬性(標題,副標題,緯度,經度,信息等)。 我需要能夠將此對象傳遞給另一個對象,該對象希望使用objectForKey方法從中提取信息,作為NSDictionary(因為這是從另一個視圖控制器獲取的內容)。

我最終做的是創建一個新的NSMutableDictionary並在其上使用setObject:forKey來傳輸每條重要信息,然后我只傳遞新創建的字典。

有沒有更簡單的方法來做到這一點?

這是相關的代碼:

// 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來檢索信息。


當然可以! 使用objc-runtime和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);

這是一篇老帖子,Richard J. Ross III的答案非常有用,但是在自定義對象的情況下(自定義類中有另一個自定義對象)。 但是,有時屬性是其他對象等,使序列化有點復雜。

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;

為了將這些類型的對象(多個自定義對象)轉換為字典,我不得不修改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];
}

我希望它能幫助別人。 完全歸功於Richard J. Ross III。

如果屬性與用於訪問字典的鍵具有相同的名稱,那么您可能剛剛使用了KVC並且具有valueForKey:而不是objectForKey

例如,給這個字典

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

和這個對象

@interface MyAnnotation : NSObject

@property (nonatomic, copy) NSString *title;

@end

如果我有一個我可以調用的字典或MyAnnotation實例, MyAnnotation

[annotation valueForKey:@"title"];

顯然,這也是另一種方式,例如

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

為了完成Richard J. Ross的方法,這個方法適用於自定義對象的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];
}

因為我有一個復雜的嵌套對象結構,所以有很多解決方案,對我來說沒什么用。 這個解決方案取決於理查德和達米恩的事情,但即興創作,因為達米恩的解決方案與命名鍵作為類​​名相關聯。

這是標題

@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];

您還可以從字典中解析對象:

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM