kvc
KVC键值查找
搜索单值成员
setValue:forKey:搜索方式
1、首先搜索setKey:方法。(key指成员变量名,首字母大写)
2、上面的setter方法没找到,如果类方法accessInstanceVariablesDirectly返回YES。那么按 _key,_isKey,key,iskey的顺序搜索成员名。(NSKeyValueCodingCatogery中实现的类方法,默认实现为返回YES)
3、如果没有找到成员变量,调用setValue:forUnderfinedKey:
valueForKey:的搜索方式
1、首先按getKey,key,isKey的顺序查找getter方法,找到直接调用。如果是BOOL、int等内建值类型,会做NSNumber的转换。
2、上面的getter没找到,查找countOfKey、objectInKeyAtindex、KeyAtindexes格式的方法。如果countOfKey和另外两个方法中的一个找到,那么就会返回一个可以响应NSArray所有方法的代理集合的NSArray消息方法。
3、还没找到,查找countOfKey、enumeratorOfKey、memberOfKey格式的方法。如果这三个方法都找到,那么就返回一个可以响应NSSet所有方法的代理集合。
4、还是没找到,如果类方法accessInstanceVariablesDirectly返回YES。那么按 _key,_isKey,key,iskey的顺序搜索成员名。
5、再没找到,调用valueForUndefinedKey。
*** 今天主要来分辨一下这几个方法的执行顺序,也许会对你有很大的帮助。
-setter-getter-(void)setValue:forKey:-(id)valueForKey:+(BOOL)accessInstanceVariablesDirectly//参考KVC、KVO探识(二)
#import@interfacemodel:NSObject@property(nonatomic,copy)NSString*name;@end
model.m
#import "model.h"
@implementationmodel@synthesizename=_name;//如果重写了setter和getter方法,@property就不会生成name属性和_name属性。所以在这里将name和_name,并且手动生成。-(NSString*)name{NSLog(@"%s",__func__);return_name;}-(void)setName:(NSString*)name{ _name=name;NSLog(@"%s",__func__);}+(BOOL)accessInstanceVariablesDirectly{NSLog(@"%s",__func__);return[superaccessInstanceVariablesDirectly];// return YES;}-(void)setValue:(id)value forKey:(NSString*)key{NSLog(@"%s",__func__); [supersetValue:value forKey:key];}-(id)valueForKey:(NSString*)key{NSLog(@"%s",__func__);//return nil;return[supervalueForKey:key];}@end
此时在ViewController.m中进行调用:
ViewController.m
#import"ViewController.h"#import"model.h"@interfaceViewController()@end@implementationViewController- (void)viewDidLoad { [superviewDidLoad]; model *modell=[[model alloc]init]; [modell setValue:@"lxh"forKey:@"name"]; [modell valueForKey:@"name"];NSLog(@"%@",modell.name);}@end
输出结果如下:
2016-03-2815:16:07.449TestKVC[673:12775]-[model setValue:forKey:]2016-03-2815:16:11.640TestKVC[673:12775]-[model setName:]2016-03-2815:16:11.640TestKVC[673:12775]-[model valueForKey:]2016-03-2815:16:11.640TestKVC[673:12775]-[model name]2016-03-2815:16:11.640TestKVC[673:12775]-[model name]2016-03-2815:16:11.641TestKVC[673:12775]lxh
问题:(先思考,后面讲解)
1.为什么没有调用:+(BOOL)accessInstanceVariablesDirectly?
注意:
经过自己打断点测试: [super setValue:value forKey:key];方法中调用了model的setter方法。同理:[super valueForKey:key];方法调用了
model的getter方法。
情况二:
model.h
#import@interfacemodel:NSObject@property(nonatomic,copy)NSString*name;@end
model.m
#import "model.h"
@implementationmodel@synthesizename=_name; -(NSString*)name{NSLog(@"%s",__func__);return_name;}-(void)setName:(NSString*)name{ _name=name;NSLog(@"%s",__func__);}+(BOOL)accessInstanceVariablesDirectly{NSLog(@"%s",__func__);return[superaccessInstanceVariablesDirectly];// return YES;}-(void)setValue:(id)value forKey:(NSString*)key{NSLog(@"%s",__func__); [supersetValue:value forKey:key];}-(id)valueForKey:(NSString*)key{NSLog(@"%s",__func__);//return nil;return[supervalueForKey:key];}@end
此时在ViewController.m中进行调用:
ViewController.m
#import"ViewController.h"#import"model.h"@interfaceViewController()@end@implementationViewController- (void)viewDidLoad { [superviewDidLoad]; model *modell=[[model alloc]init]; [modell setValue:@"lxh"forKey:@"_name"]; [modell valueForKey:@"_name"];NSLog(@"%@",modell.name);}@end
输出结果如下:
2016-03-2815:23:43.665TestKVC[703:15739]-[model setValue:forKey:]2016-03-2815:23:48.416TestKVC[703:15739]+[model accessInstanceVariablesDirectly]2016-03-2815:23:57.708TestKVC[703:15739]-[model valueForKey:]2016-03-2815:23:57.708TestKVC[703:15739]+[model accessInstanceVariablesDirectly]2016-03-2815:23:57.709TestKVC[703:15739]-[model name]2016-03-2815:23:57.709TestKVC[703:15739]lxh
问题:
1.为什么此时没有调用setter、getter方法,而是调用了+[model accessInstanceVariablesDirectly]?
2.为什么第二种情况没有调用setter、getter(现有的)方法,也能输出正确结果?
注意:
经过打断点发现:[super setValue:value forKey:key];方法中调用了+accessInstanceVariablesDirectly这个方法。同理:[super valueForKey:key];方法也调用了+accessInstanceVariablesDirectly。
对比前两种情况,你会感觉很迷惑,但是请坚持住,接着往下看
第三种情况:
model.h
#import@interfacemodel:NSObject@property(nonatomic,copy)NSString*name;@end
model.m
#import "model.h"
@implementationmodel@synthesizename=_name;//如果重写了setter和getter方法,@property就不会生成name属性和_name属性。所以在这里将name和_name,并且手动生成。-(NSString*)name{NSLog(@"%s",__func__);return_name;}-(void)setName:(NSString*)name{ _name=name;NSLog(@"%s",__func__);}+(BOOL)accessInstanceVariablesDirectly{NSLog(@"%s",__func__);return[superaccessInstanceVariablesDirectly];// return YES;}-(void)setValue:(id)value forKey:(NSString*)key{NSLog(@"%s",__func__); [supersetValue:value forKey:key];}-(void)set_name:(id)name{ _name=name;NSLog(@"%s",__func__);}-(id)_name{NSLog(@"%s",__func__);return_name;}-(id)valueForKey:(NSString*)key{NSLog(@"%s",__func__);//return nil;return[supervalueForKey:key];}@end
此时在ViewController.m中进行调用:
ViewController.m
#import"ViewController.h"#import"model.h"@interfaceViewController()@end@implementationViewController- (void)viewDidLoad { [superviewDidLoad]; model *modell=[[model alloc]init]; [modell setValue:@"lxh"forKey:@"_name"]; [modell valueForKey:@"_name"];NSLog(@"%@",modell.name);}@end
输出结果如下:
2016-03-2815:38:40.383TestKVC[793:21114]-[model setValue:forKey:]2016-03-2815:38:42.575TestKVC[793:21114]-[model set_name:]2016-03-2815:38:43.833TestKVC[793:21114]-[model valueForKey:]2016-03-2815:38:43.834TestKVC[793:21114]-[model _name]2016-03-2815:38:43.834TestKVC[793:21114]-[model name]2016-03-2815:38:43.834TestKVC[793:21114]lxh
问题:
1.为什么此时调用了setter、getter方法,但是是set_name和_name?
2.为什么此时model的name依旧已经被赋值过了?
对比前两种情况,你会感觉很迷惑,但是请坚持住,接着往下看
看完第三种情况貌似更疯了,不要着急,马上做分析:
分析(现象分析)
1.对比三种情况你会发现:只要调用了setter、getter方法,就不会去调用:+(BOOL)accessInstanceVariablesDirectly方法,反之也是如此。
2.并且赋值阶段都是有[super setValue:value forKey:key];去实现调用的。取值同样是由[super setValue:value forKey:key];去实现的。
分析(深层次)
[super setValue:value forKey:key]方法内部实现赋值有两种方式:一种是调用setter,一种是直接赋值例如:_name=name;
步骤如下:
首先:①如果是采用name去设置的话,[super setValue:value forKey:key]会去查找是否有对应的setName: 方法,如果有,就调用setName:去进行赋值。
如果没有(例如key:_name)则会调用:+(BOOL)accessInstanceVariablesDirectly方法去进行匹配(注意此时该方法的返回值默认是Yes,只有YES才去匹配name和_name)
作者:Peak_One
链接:https://www.jianshu.com/p/8c5d313e50ac
來源:
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
-----------------------------------------------kvo -----------------