43

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

一种可能的方法是检查 -valueForKey: 方法,但这似乎相当不雅!

例子:

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

有没有更好的方法来做到这一点?

4

4 回答 4

60

如果您正在创建正在检查的对象,您可以覆盖valueForUndefinedKey:setValue:forUndefinedKey做一些比引发异常更有用的事情。

另一方面,如果你试图在运行时内省你不知道的对象,你将不得不使用运行时方法来做到这一点。您可以使用objective-c运行时本身并调用class_copyPropertyListprotocol_copyPropertyList处理它们,或者使用Foundation并respondsToSelector为给定属性调用KVC getter/setter的对象,例如,对于foo您会调用类似的属性[someObject respondsToSelector:NSSelectorFromString(@"foo")];

于 2009-12-08T18:03:14.457 回答
6

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

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

于 2009-12-08T18:26:29.273 回答
2

继@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);
}

用法:

快速:将代码片段添加到您的桥接头中,然后:

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

if SOMETHING.responds(to: sel) {SOMETHING.setValue(value, forKeyPath: key)}
于 2018-02-16T18:59:05.657 回答
0

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

  @try {
    id *value = [instance valueForKey:@"myProperty"];
  }
  @catch (NSException * e) {
    // Key did not exist
  }
于 2020-07-23T02:56:41.690 回答