使用与 属性 名称不同的键从 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:
.
转向另一个方向
我需要根据远程服务器通过 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:
.