使用与 属性 名称不同的键从 NSDictionary 设置对象的属性

Setting an object's properties from an NSDictionary with keys that are not identical to the property names

我需要根据远程服务器通过 JSON 提供的 NSDictionary 设置一堆对象属性。我不想覆盖字典中没有的属性。

因为有很多属性,所以我有一长串如下所示的语句:

if (dictionary[@"address_1"] != [NSNull null]) 
    self.configuration.userAddress1 = dictionary[@"address_1"];

字典中的关键字与属性名称不一致;有两个不同的系统,它们分别成长起来,我正试图让它们一起工作。

也许我 Ruby 编码太多了,但似乎 Objective-C 中应该有更好的习惯用法来执行此操作。有什么想法吗?

不,不是rubyish,因为Objective-C是动态类型的。您可以使用键值编码来做到这一点:

for (NSString *key in dictionary)
{
    id value = dictionary[key];
    [self.configuration setValue:value forKey:key];
}

但是看到我的评论here.

顺便说一句:如果字典中不存在键,结果是 nil 而不是 [NSNull null]

因此,如果您不想设置字典中没有的属性,则无需执行任何其他操作。如果您不想设置字典中值为 [NSNull null] 的属性,您仍然可以添加检查。

如果不想设置为null的:

for (NSString *key in dictionary)
{
  id value = dictionary[key];
  if (value != [NSNull null] )
  {
    [self.configuration setValue:value forKey:key];
  }
}

如果你想用 nil 设置 null:

for (NSString *key in dictionary)
{
  id value = dictionary[key];
  if (value == [NSNull null] )
  {
    value = nil;
  }
  [self.configuration setValue:value forKey:key];
}

Objective-C 中的一个可能的成语是:不要 有很多对象属性。有一个属性,一本字典!现在很容易根据传入的字典填充该字典。

听起来您想要一个简单的地图解决方案 - 您可以像这样手动滚动一个

[@{
   @"address_1" : @"address1",
   @"address_2" : @"address2",
   ...
   } enumerateKeysAndObjectsUsingBlock:^(NSString *remoteKey, NSString *localKey, BOOL *stop) {
     id remoteValue = dictionary[remoteKey];

     if (![remoteValue isEqual:NSNull.null]) {
       [self.configuration setValue:remoteValue forKey:localKey];
     }
   }];

这应用了一些基本的 Null 检查逻辑并允许 remote/local 对象具有不同的 属性 名称

另一种方法是覆盖 class 中的 -setValue:forUndefinedKey: 并将键映射到那里。

- (void) setValue:(id)value forUndefinedKey:(NSString*)key
{
    static dispatch_once_t once;
    static NSDictionary* map;
    dispatch_once(&once, ^{
        map = @{
                 @"address_1" : @"address1",
                 @"address_2" : @"address2",
                 // ...
               };
    });

    NSString* newKey = map[key];
    if (newKey)
        [self setValue:value forKey:newKey];
    else
        [super setValue:value forUndefinedKey:key];
}

现在您可以 -setValuesForKeysWithDictionary: 与原始词典一起使用。该方法会将 nil 替换为 NSNull 对象,因此您必须决定这是否是您想要的。

如果需要,您也可以通过覆盖 -valueForUndefinedKey:.

转向另一个方向