使用任意方法进行键值编码,而不仅仅是属性

时间:2014-10-16 19:28:30

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

似乎-valueForKey:-valueForKeyPath:使用任意方法,不仅适用于属性。这看起来很方便:

I first stumbled upon it in Interface Builder,然后做了一些实验:

//  Thing.h
#import <Foundation/Foundation.h>

@interface Thing : NSObject
- (BOOL) alwaysYES;
- (BOOL) alwaysNO;
@end

//  Thing.m
#import "Thing.h"
@implementation Thing

- (BOOL) alwaysYES
{
    return YES;
}

- (BOOL) alwaysNO
{
    return NO;
}
@end

我可以通过-valueForKey:-valueForKeyPath: 调用这些方法,尽管它们是普通方法而且没有属性

Thing *aThing = [[Thing alloc] init];
id result;
result = [aThing valueForKey:@"alwaysYES"];
NSLog(@"result is: %@", result);
result = [aThing valueForKeyPath:@"alwaysNO"];
NSLog(@"result is: %@", result);

编译,运行并给出正确的结果。这记录在哪里?我可以安全地使用它吗?我怎么能理解呢?

3 个答案:

答案 0 :(得分:3)

Cocoa的键值编码(KVC)系统比Objective-C中对显式属性(用@property声明)的支持更旧,因此KVC是根据方法定义的,而不是属性。

“Default Search Pattern for valueForKey:” in the Key-Value Coding Programming Guide阐明了valueForKey:如何决定做什么。它首先查找(除其他外)一个方法,其名称正是您传递给valueForKey:的密钥。以下是文档中引用的完整搜索模式:

  
      
  1. 在接收者的类中搜索名称与模式get<Key><key>is<Key>匹配的访问者方法。如果找到这样的方法,则调用它。如果方法的结果类型是对象指针类型,则只返回结果。如果结果的类型是NSNumber转换支持的标量类型之一,则返回NSNumber。否则,转换完成并返回NSValue。任意类型的结果将转换为NSValue个对象,而不仅仅是NSPointNSRangeNSRectNSSize类型。

  2.   
  3. 否则(没有找到简单的访问器方法),在接收器的类中搜索名称与模式countOf<Key>objectIn<Key>AtIndex:匹配的方法(对应于{定义的基本方法) {1}}类)和NSArray(对应<key>AtIndexes:方法NSArray)。   如果找到objectsAtIndexes:方法和其他两种可能方法中的至少一种,则返回响应所有countOf<Key>方法的集合代理对象。发送到集合代理对象的每条NSArray消息都会导致NSArraycountOf<Key>objectIn<Key>AtIndex:消息的某种组合被发送到<key>AtIndexes:的原始接收方。如果接收者的类还实现了一个名称与模式valueForKey:匹配的可选方法,那么该方法将在适当时使用,以获得最佳性能。

  4.   
  5. 否则(没有找到简单的访问器方法或数组访问方法集),在接收器的类中搜索名称与模式get<Key>:range:countOf<Key>匹配的三种方法,和enumeratorOf<Key>(对应于memberOf<Key>:类定义的基本方法)。   如果找到所有三个方法,则返回响应所有NSSet方法的集合代理对象。发送到集合代理对象的每条NSSet消息都会导致NSSetcountOf<Key>enumeratorOf<Key>消息的某种组合被发送到memberOf<Key>:的原始接收方

  6.   
  7. 否则(没有找到简单的访问器方法或集合访问方法),如果接收者的类方法valueForKey:返回accessInstanceVariablesDirectly,则在接收者的类中搜索实例变量其名称与模式YES_<key>_is<Key><key>按此顺序匹配。如果找到这样的实例变量,则返回接收器中的实例变量的值。如果结果的类型是is<Key>转换支持的标量类型之一,则返回NSNumber。否则,转换完成并返回NSNumber。任意类型的结果将转换为NSValue个对象,而不仅仅是NSValueNSPointNSRangeNSRect类型。

  8.   
  9. 如果上述情况均未发生,则返回默认实现调用NSSize的结果。

  10.   

答案 1 :(得分:1)

这与您可以使用属性语法调用这些方法的事实并行:

BOOL ok = aThing.alwaysYES

在这种情况下,在您的情况下,完全相同的事情发生:the first thing the runtime tries将此视为getter方法。你写的一个getter方法。

至于你的问题&#34;我可以安全地使用它吗?安全地是,但你正在做的事情有点愚蠢,因为你知道(并且声明)这些方法存在。 KVC正在探索是否存在方法。如果您有理由通过字符串名称指定其中一种方法,则有比使用KVC更好的方法来调用它。

答案 2 :(得分:0)

属性在运行时没什么特别之处;他们生成一个符合KVC的getter和setter(如果不是readonly);例如:

@property NSString *aString;

将生成:

- (NSString)aString {
   ...
}

- (void)setAString(NSString *string) {
   ...
}

就像你在标题中声明了这些方法一样(它本身是可选的)。

请参阅Key Value Coding Fundamentals文档。