如何使用键值编码判断对象是否存在密钥?

时间:2009-12-08 17:55:37

标签: iphone objective-c properties key-value-coding

我想测试一个对象在iPhone SDK中是否有可写的@property。

这样做的一种可行方法是检查-valueForKey:方法,但这看起来相当不优雅!

示例:

  @try {
    id *value = [instance valueForKey:@"myProperty"];
  }
  @catch (NSException * e) {
    // Key did not exist
  }

有更好的方法吗?

4 个答案:

答案 0 :(得分:54)

如果您要创建正在检查的对象,则可以覆盖valueForUndefinedKey:setValue:forUndefinedKey以执行比引发异常更有用的操作。

另一方面,如果您试图在运行时内省您不了解的对象,则必须使用运行时方法来执行此操作。您可以使用objective-c运行时本身并调用class_copyPropertyListprotocol_copyPropertyList并处理这些内容,或使用Foundation并在对象上调用respondsToSelector以获取KVC getter / setter给定属性,例如,对于属性foo,您可以调用类似[someObject respondsToSelector:NSSelectorFromString(@"foo")];的内容。

答案 1 :(得分:5)

通常,无法确定对象是否具有给定键的值。实例可能决定从其-valueForUndefinedKey:方法返回其他未定义键的值。或者它可能让默认实现抛出异常。现代Objective-C(2.0)对象经常在其公共API中声明相关属性。对于这些对象,您可以使用Objective-C运行时的class_copyPropertyListprotocol_copyPropertyList来获取可用属性的列表。您还可以模拟KVC搜索列表,如果实例响应适当的getter方法,则通过repondsToSelector:进行测试。最后,您可以使用运行时的class_copyIvarList来检查ivars是否有合适的ivar。这是不应该做的很多工作。它不能保证您在发送valueForKey:消息时知道对象实例是否会引发异常并且它表示更大的问题......

如果您有一组对象必须全部为给定键提供值,但有些对象没有,那么您就遇到了设计问题。您应该定义一个适当的接口(Objective-C中的@protocol)来声明所需的属性。然后,您可以测试是否符合此协议,或者使用编译器为您执行某些编译时类型检查,以确保实例符合协议(如果您传递单个实例)。

答案 2 :(得分:0)

继续@Jason Coco回答。

以下是关于如何专门检查您尝试设置的属性的“设置”选择器的提供。

这是纯粹的污秽,但它有效,我发现自己正在使用它。你已被警告过..

NS_INLINE SEL _Nonnull IBPropertySetSelectorForPropertyName(NSString*_Nonnull propertyName)
{

    NSString* firstLetter = [propertyName substringToIndex:1];
    propertyName = [propertyName substringFromIndex:1];

    propertyName = [[NSString alloc] initWithFormat:@"set%@%@:",firstLetter.capitalizedString,propertyName];

    return NSSelectorFromString(propertyName);
}

<强>用法:

在swift中: 将代码段添加到桥接标题中:

let key = "someKey"    
let sel = IBPropertySetSelectorForPropertyName(key)

if SOMETHING.responds(to: sel) {SOMETHING.setValue(value, forKeyPath: key)}

答案 3 :(得分:0)

您在问题中提出的try / catch方法是了解valueForKey:是否会引发异常的唯一可靠方法。

  @try {
    id *value = [instance valueForKey:@"myProperty"];
  }
  @catch (NSException * e) {
    // Key did not exist
  }