15

私は最終的に理解した何かに出くわしましたが、おそらくそれを達成するためのはるかに効率的な方法があると思います.

いくつかのプロパティ (タイトル、サブタイトル、緯度、経度、情報など) を持つオブジェクト (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 を使用して情報を取得します。


4

6 に答える 6

58

確実なこと!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);
于 2012-04-25T15:19:29.637 に答える
11

これは古い投稿であり、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.RossIIIのAnswerを少し変更する必要がありました。

+(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.ロスIIIに行きます。

于 2012-10-15T06:41:39.867 に答える
5

プロパティがディクショナリへのアクセスに使用されるキーと同じ名前である場合は、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"];
于 2012-04-25T15:08:04.413 に答える
2

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];
}
于 2014-03-07T18:53:51.570 に答える