如何使用键值编码判断对象是不是存在键?
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_copyPropertyList
或protocol_copyPropertyList
并处理它们,或者使用Foundation并在对象上调用respondsToSelector
以获取给定属性的KVC getter/setter,例如, foo
的属性,您可以调用类似 [someObject respondsToSelector:NSSelectorFromString(@"foo")];
的名称。
【讨论】:
【参考方案2】:一般来说,没有办法确定对象是否具有给定键的值。一个实例可以决定从它的-valueForUndefinedKey:
方法返回一个未定义键的值。或者它可能让默认实现抛出异常。现代 Objective-C (2.0) 对象经常在其公共 API 中声明相关属性。对于这些对象,您可以使用 Objective-C 运行时的 class_copyPropertyList
或 protocol_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
【讨论】:
以上是关于如何使用键值编码判断对象是不是存在键?的主要内容,如果未能解决你的问题,请参考以下文章