取值
当调用valueForKey:@”name“
的代码时,KVC对key
的搜索方式不同于setValue:属性值 forKey:@”name“
,其搜索方式如下:
- 首先按
get<Key>
,<key>
,is<Key>
的顺序方法查找getter
方法,找到的话会直接调用。如果是BOOL
或者Int
等值类型, 会将其包装成一个NSNumber
对象。 - 如果上面的
getter
没有找到,KVC则会查找countOf<Key>
,objectIn<Key>AtIndex
或<Key>AtIndexes
格式的方法。如果countOf<Key>
方法和另外两个方法中的一个被找到,那么就会返回一个可以响应NSArray
所有方法的代理集合(它是NSKeyValueArray
,是NSArray
的子类),调用这个代理集合的方法,或者说给这个代理集合发送属于NSArray
的方法,就会以countOf<Key>
,objectIn<Key>AtIndex
或<Key>AtIndexes
这几个方法组合的形式调用。还有一个可选的get<Key>:range:
方法。所以你想重新定义KVC的一些功能,你可以添加这些方法,需要注意的是你的方法名要符合KVC的标准命名方法,包括方法签名。 - 如果上面的方法没有找到,那么会同时查找
countOf<Key>
,enumeratorOf<Key>
,memberOf<Key>
格式的方法。如果这三个方法都找到,那么就返回一个可以响应NSSet
所的方法的代理集合,和上面一样,给这个代理集合发NSSet
的消息,就会以countOf<Key>
,enumeratorOf<Key>
,memberOf<Key>
组合的形式调用。
如果还没有找到,再检查类方法
+ (BOOL)accessInstanceVariablesDirectly
,如果返回YES(默认行为),那么和先前的设值一样,会按
_<key>,_is<Key>,<key>,is<Key>
的顺序搜索成员变量名,这里不推荐这么做,因为这样直接访问实例变量破坏了封装性,使代码更脆弱。如果重写了类方法
+ (BOOL)accessInstanceVariablesDirectly
返回NO的话,那么会直接调用
valueForUndefinedKey:
还没有找到的话,调用
valueForUndefinedKey:
如果还没有找到,再检查类方法
+ (BOOL)accessInstanceVariablesDirectly
,如果返回YES(默认行为),那么和先前的设值一样,会按
_<key>,_is<Key>,<key>,is<Key>
的顺序搜索成员变量名,这里不推荐这么做,因为这样直接访问实例变量破坏了封装性,使代码更脆弱。如果重写了类方法
+ (BOOL)accessInstanceVariablesDirectly
返回NO的话,那么会直接调用
valueForUndefinedKey:
还没有找到的话,调用
valueForUndefinedKey:
#import <Foundation/Foundation.h>
@interface ObtainValueClass : NSObject
@property (nonatomic,readwrite,assign) NSUInteger count;
@property (nonatomic,copy) NSString* arrName;
-(void)incrementCount;
-(NSUInteger)countOfNumbers;
-(id)objectInNumbersAtIndex:(NSUInteger)index;
@end
#import "ObtainValueClass.h"
@implementation ObtainValueClass
-(void)incrementCount{
NSLog(@"%@", NSStringFromSelector(_cmd));
// NSLog(@"%lu", (unsigned long)self.count);
self.count ++;
}
-(NSUInteger)countOfNumbers{
NSLog(@"%@", NSStringFromSelector(_cmd));
return self.count;
}
-(id)objectInNumbersAtIndex:(NSUInteger)index{ //当key使用numbers时,KVC会找到这两个方法。
NSLog(@"%@", NSStringFromSelector(_cmd));
return @(index * 2);
}
-(NSInteger)getNum{ //第一个,自己一个一个注释试
NSLog(@"%@", NSStringFromSelector(_cmd));
return 10;
}
-(NSInteger)num{ //第二个
NSLog(@"%@", NSStringFromSelector(_cmd));
return 11;
}
-(NSInteger)isNum{ //第三个
NSLog(@"%@", NSStringFromSelector(_cmd));
return 12;
}
@end
//问题三
//KVC valueForKey:对 key的搜索机制
//首先按get<Key>,<key>,is<Key>的顺序方法查找getter方法,找到的话会直接调用。如果是BOOL或者Int等值类型, 会将其包装成一个NSNumber对象。
ObtainValueClass * obj = [[ObtainValueClass alloc] init];
NSNumber * num = [obj valueForKey:@"num"];
NSLog(@"%@",num);
//如果上面的getter没有找到,KVC则会查找countOf<Key>,objectIn<Key>AtIndex或<Key>AtIndexes格式的方法。如果countOf<Key>方法和另外两个方法中的一个被找到,那么就会返回一个可以响应NSArray所有方法的代理集合(它是NSKeyValueArray,是NSArray的子类),调用这个代理集合的方法,或者说给这个代理集合发送属于NSArray的方法,就会以countOf<Key>,objectIn<Key>AtIndex或<Key>AtIndexes这几个方法组合的形式调用。还有一个可选的get<Key>:range:方法。所以你想重新定义KVC的一些功能,你可以添加这些方法,需要注意的是你的方法名要符合KVC的标准命名方法,包括方法签名。
id numbers = [obj valueForKey:@"numbers"];
NSLog(@"%@",NSStringFromClass([numbers class]));//简单来说就是如果你在自己的类自定义了KVC的实现,并且实现了上面的方法,那么恭喜你,你可以将返回的对象当数组(NSArray)用了
NSLog(@"0:%@ 1:%@ 2:%@ 3:%@",numbers[0],numbers[1],numbers[2],numbers[3]);
[obj incrementCount]; //count加1
NSLog(@"%lu",(unsigned long)[numbers count]);
[obj incrementCount]; //count再加1
NSLog(@"%lu",(unsigned long)[numbers count]); //打印出2
[obj setValue:@"newName" forKey:@"arrName"];
NSString* name = [obj valueForKey:@"arrName"];
NSLog(@"%@",name);