KVC全称Key Value Coding也就是键值编码,当在同时实现setter和getter时,类中的@property不会自动生成带下滑线的成员变量,而我们如果去定义了一个带下划线的成员变量NSString * _bookName; 然后我们在外面使用的时候[stu setValue:@"kkk" forKey:@"_bookName"]; 也是已经给bookName赋值了,,因为Xcode
会默认将self.bookName
与自定义成员变量_bookName
关联。
当然如果我们直接使用@synthesize bookName = _bookName; 然后在外面用KVC对_bookName赋值的话也是可以赋值的,因为写了这句话之后其实就相当于是把bookName和_bookName给联系起来了。
当然如果我们采取@synthesize bookName = _obj; 一样在外面通过KVC给_obj设置值一样会关联到bookName。
一般来说在KVC中我们使用了ValueForKey想去寻找key对应的值的话,会先去找相关的方法,再去找相关的变量。
如果说我们相关的方法找不到的时候,才会去找相关的变量,这点可以在下面中进行证明,当我们定义了下面这样的属性
@property (nonatomic ,strong)NSString *name;
//以及我们写了下面这个方法
-(NSString *)getName
{
_name=@"qqq";
return @"kkdjskja";
}
//然后根据key是name去获取值,获取到的是kkdjskja,而我们打印student的name是qqq
NSString * str = [student valueForKey:@"name"];
还有需要了解的是,如果我们的属性是有用readonly修饰的,并且实现了下面的这个方法,那么我们是无法用KVC给这个属性赋值的,这个方法默认返回 YES,也就是说在不存在满足条件的方法时,允许直接访问属性对应的实例变量,如果我们返回NO就表示不允许访问。但如果去掉readonly还是可以赋值的。
以及我们在使用[student setValue:@"qweqwe" forKey:@"name"];赋值的时候回优先去找setName的方法,如果找不到方法然后再去找成员变量,然后再去赋值。当然这个前提是下面的这个方法要返回YES。
+(BOOL)accessInstanceVariablesDirectly
{
return NO;
}
还有就是我们在类扩展中定义的变量也是无法通过KVC进行赋值的,如果我们上面的这个方法也返回了NO。
@interface Student()
{
NSString * name;
}
当然也无法通过valueForKey去访问它的值。去寻找相应的Value是优先去找get<Key>然后再去找<key>方法。
还有就是当我们有一个变量是基本数据类型的时候,使用valueForKey会帮我们转换成NSNumber类型。
如果我们定义的是成员变量NSString * _name;则我们在使用setValue ForKey赋值的时候可能会调用两个方法,如果两个方法都实现了就只会调用优先级高的也就是setName方法
优先级低的是setIsName方法。但如果我们定义的是属性name,如果去使用KVC赋值的时候以及只实现了setIsName方法也不会去调用setIsName方法。
-(void)setName:(NSString *)name
{
NSLog(@"dadaokiji");
}
-(void)setIsName:(NSString *)name
{
NSLog(@"12131");
}
我们如果在一个类中有这些成员变量的话,那么赋值的过程是有顺序的,如下所示,比如说我们通过valueForKey:@"name"去获取值,获取到的顺序如下所示,也就是说如果不存在满足条件的方法,以及+ (BOOL)accessInstanceVariablesDirectly 返回 YES,那么就会以 _<key> , _is<Key> , <key> , is<Key> 的顺序查找是否存在对应的key。
NSString * isName;//4
NSString * _isName;//2
NSString * name;//3
NSString * _name;//1
还有一个就是我们如果再类的内部有一个属性是大写开头的比如说Nook,我们在外部用KVC把key设置成nook也是可以赋值的。