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

发布于 2024-08-13 21:34:54 字数 270 浏览 10 评论 0原文

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

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

示例:

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

有更好的方法吗?

I'd like to test whether an object has a writeable @property in the iPhone SDK.

One possible way of doing this is to check the -valueForKey: method, but that seems rather inelegant!

Example:

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

Is there a better way of doing this?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

沉鱼一梦 2024-08-20 21:34:54

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

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

If you are creating the object that is being checked, you could override valueForUndefinedKey: and setValue:forUndefinedKey to do something more useful than raising an exception.

If, on the other hand, you are trying to introspect objects you don't know about at runtime, you will have to use the runtime methods to do that. You can either use the objective-c runtime itself and call either class_copyPropertyList or protocol_copyPropertyList and deal with those, or use Foundation and call respondsToSelector on the object for the KVC getter/setters for a given property, e.g., for a property foo you would call something like [someObject respondsToSelector:NSSelectorFromString(@"foo")];.

久随 2024-08-20 21:34:54

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

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

There is no way, in general, to determine if an object has a value for a given key. An instance may decide to return a value for an otherwise undefined key from its -valueForUndefinedKey: method. Or it may let the default implementation throw an exception. Modern Objective-C (2.0) objects often declare relevant properties in their public API. For these objects, you can use the Objective-C runtime's class_copyPropertyList or protocol_copyPropertyList to get a list of the available properties. You can also emulate the KVC search list, testing via repondsToSelector: if the instance responds to an appropriate getter method. Finally you could use the runtime's class_copyIvarList to check the ivars for an appropriate ivar. This is a lot of work that you shouldn't be doing. It won't guarantee that you know whether an object instance will raise an exception when sent a valueForKey: message and it indicates a bigger issue...

If you have a collection of objects that must all provide a value for a given key, but some don't, you have a design problem. You should define an appropriate interface (a @protocol in Objective-C) that declares the needed properties. You can then test for conformance to this protocol, or make use of the compiler to do some compile-time type checking for you to make sure instance conform to the protocol (if you're passing around single instances).

段念尘 2024-08-20 21:34:54

以下是@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)}

Following on from @Jason Coco answer.

Here is my offering on how to check specifically for the "set" selectors existence of the property you're trying to set.

This is pure filth but it works and I've found myself using it. You've been warned..

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

Usage:

In swift:
Add the code snippet to your bridging header then:

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

if SOMETHING.responds(to: sel) {SOMETHING.setValue(value, forKeyPath: key)}
﹎☆浅夏丿初晴 2024-08-20 21:34:54

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

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

The try/catch approach you propose in your question is the only reliable way of knowing whether valueForKey: will throw an exception.

  @try {
    id *value = [instance valueForKey:@"myProperty"];
  }
  @catch (NSException * e) {
    // Key did not exist
  }
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文