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

Posted

技术标签:

【中文标题】如何使用键值编码判断对象是不是存在键?【英文标题】:How do you tell if a key exists for an object using Key-Value Coding?如何使用键值编码判断对象是否存在键? 【发布时间】:2010-12-24 12:46:59 【问题描述】:

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

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

例子:

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

有更好的方法吗?

【问题讨论】:

***.com/a/3059053/294884 【参考方案1】:

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

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

【讨论】:

【参考方案2】:

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

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

【讨论】:

也许有助于澄清!该应用程序在多个运行时上运行,并提供不同版本的库。在一个版本中,我需要设置(原始类型)的属性不存在 - 因此,需要检查它是否存在。 如果控制有问题的类,因此知道类将 i>响应包含您房产的库版本中的相应选择器,请使用respondsToSelector:。在这种情况下,您应该直接使用 getter 方法而不是 valueForKey:,因为它会更快。 不幸的是,我无法控制有问题的课程。为了让事情变得更简单,我改用NSInvocation 来设置原始类型属性,而不是使用键值编码(我确实在使用respondsToSelector:)。【参考方案3】:

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

用法:

迅速: 然后将代码 sn-p 添加到您的桥接头中:

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

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

【讨论】:

为什么不在Swift 中使用NSSelectorFromString("setPropertyName:") 只有Selector("selectorName:") 会生成警告。 NSSelectorFromString(...) 没有。显然它无论如何都不安全。【参考方案4】:

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

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

【讨论】:

以上是关于如何使用键值编码判断对象是不是存在键?的主要内容,如果未能解决你的问题,请参考以下文章

js中如何判断一个DOM对象是不是存在?

检查对象数组中是不是存在具有特定键值的对象

如何判断js里的对象是不是存在

JS判断两个对象内容是不是相等

Java求助:如何判断某对象是不是存在?如果不存在,创建该对象

我如何判断一个对象是不是附加了键值观察器