KVC全称是Key-Value Code,俗称键值对,可以通过一个key来访问某个属性。
- 常见的API有
设置属性值:setValue:<#(nullable id)#> forKey:<#(nonnull NSString *)#>
setValue:<#(nullable id)#> forKeyPath:<#(nonnull NSString *)#>
获取属性值:valueForKey:<#(nonnull NSString *)#>
valueForKeyPath:<#(nonnull NSString *)#>
1. forKey 和 forKeyPath 设置值的区别
【 例 】
// forKey用法
Person *p = [[Person alloc]init];
[p setValue:@10 forKey:@"age"];
NSLog(@"-- %ld",p.age); // -- 10
// forKeyPath用法
Person *p = [[Person alloc]init];
//[p setValue:@10 forKey:@"age"];
[p setValue:@20 forKeyPath:@"age"];
NSLog(@"-- %ld",p.age); //-- 20
单从这两个基础设值来看,用法一样,没有太大区别,我们来看下差异之处:
比如有这样一个Person类,里面有一个Student类
Person.h
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
@interface Student : NSObject
@property (nonatomic,assign) NSInteger weight;
@end
@interface Person : NSObject
@property (nonatomic, assign) NSInteger age;
@property (nonatomic, strong) Student *stu;
@end
NS_ASSUME_NONNULL_END
Person.m
@implementation Student
@end
@implementation Person
@end
代码示例:
Person *p = [[Person alloc]init];
Student *stu = [[Student alloc]init];
p.stu = stu;
//[p setValue:@10 forKey:@"age"];
//[p setValue:@20 forKeyPath:@"age"];
[p setValue:@30 forKeyPath:@"stu.weight"];
NSLog(@"-- %ld",p.stu.weight);
2. forKey 和 forKeyPath 取置值的区别
【 例 】
Person *p = [[Person alloc]init];
p.age = 10;
NSLog(@"-- %@",[p valueForKey:@"age"]);
NSLog(@"-- %@",[p valueForKeyPath:@"age"]);
还是单从这两个基础设值来看,用法一样,没有太大区别,我们来看下差异之处:
Person *p = [[Person alloc]init];
Student *stu = [[Student alloc]init];
p.stu = stu;
p.age = 10;
p.stu.weight = 30;
NSLog(@"-- %@",[p valueForKey:@"age"]);
NSLog(@"-- %@",[p valueForKeyPath:@"stu.weight"]);
【小结】
- keyPath 相当于根据路径去寻找属性,一层一层往下找;
- key 是直接根据属性名字设置值,如果按路径找会报错
【 拓展 】
setValue / valueForKeyPath
方法也会触发KVO事件,如下图所示:
setValue:forKey: 赋值的原理
步骤:当我们设置setValue:forKey:时;
① 首先会查找setKey:、_setKey: (按顺序查找);
② 如果有直接调用,如果没有,先查看accessInstanceVariablesDirectly方法;+ (BOOL)accessInstanceVariablesDirectly{ return YES; /// 可以直接访问成员变量 //return NO; /// 不可以直接访问成员变量, /// 直接访问会报NSUnkonwKeyException错误 }
③ 如果可以访问会按照 _key、_isKey、key、iskey的顺序查找成员变量,找到直接赋值;
④ 未找到报错NSUnkonwKeyException错误
【 小结 】
所以,setValue:@10 forKey:@"age"
修改age,核心还是应为调用了willChangeValueForKey:key
和didChangeValueForKey:key
。
valueForKey: 取值的原理
步骤:当我们设置valueForKey:时;
① kvc取值按照 getKey、key、iskey、_key 顺序查找;② 存在直接调用,如果没找到,同样会先查看accessInstanceVariablesDirectly方法;
+ (BOOL)accessInstanceVariablesDirectly{ return YES; /// 可以直接访问成员变量 //return NO; /// 不可以直接访问成员变量, /// 直接访问会报NSUnkonwKeyException错误 }
③ 如果可以访问会按照 _key、_isKey、key、iskey的顺序查找成员变量,找到直接赋值;
④ 未找到报错NSUnkonwKeyException错误。