1、KVC简介
KVC的全称是Key-Value Coding,俗称“键值编码”,可以通过一个key来访问某个属性
常见的API有:
//设置属性值
- (void)setValue:(id)value forKeyPath:(NSString *)keyPath;
- (void)setValue:(id)value forKey:(NSString *)key;
//获取属性值
- (id)valueForKeyPath:(NSString *)keyPath;
- (id)valueForKey:(NSString *)key;
2、探究KVC本质
创建文件MJPerson.h
#import <Foundation/Foundation.h>
@interface MJPeroson : NSObject
//1.这样直接定义变量,在没有set、get方法的时候,会按照_age、_isAge、age、isAge的方法去查找成员变量
{
int _age;
int _isAge;
int age;
int isAge;
}
//2.这种定义属性,会自动生成对应的set方法和get方法
//@property(nonatomic,assign) int age;
@end
创建文件MJPerson.m
#import "MJPeroson.h"
@implementation MJPeroson
-(void)setAge:(int)age{
// _age = age;//这句代码不写,值不会改变,但是依然会触发KVO
NSLog(@"执行setAge方法");
}
-(void)_setAge:(int)age{
// _age = age;//这句代码不写,值不会改变,但是依然会触发KVO
NSLog(@"执行_setAge方法");
}
+(BOOL)accessInstanceVariablesDirectly{
//这个类方法是默认YES,在MJPerson类alloc的时候会执行
//返回NO表示,不允许直接访问成员变量,接抛出异常
//返回YES表示,允许直接访问成员变量,按照_age、_isAge、age、isAge的顺序去访问成员变量,如果以上四个成员变量都没有的话,也会抛出异常
NSLog(@"执行accessInstanceVariablesDirectly方法");
return YES;
}
@end
ViewController.m文件
#import "ViewController.h"
#import "MJPeroson.h"
@interface ViewController ()
@property(nonatomic,strong)MJPeroson *person;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.person = [[MJPeroson alloc] init];
NSKeyValueObservingOptions options = NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld;
[self.person addObserver:self forKeyPath:@"age" options:options context:nil];
}
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
// 这三种方法都可以成功设置self.person的age属性为10
// [self.person setValue:@10 forKey:@"age"];
// [self.person setValue:@(10) forKey:@"age"];
[self.person setValue:[NSNumber numberWithInteger:10] forKey:@"age"];
}
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context{
NSLog(@"监听到%@的属性%@发生了变化----%@",object,keyPath,change);
}
-(void)dealloc{
[self.person removeObserver:self forKeyPath:@"age"];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
@end
原理图如下:
3、总结:
<1>通过KVC修改属性会触发KVO么?
肯定会。
从上面也可以看出,当没有set方法的时候,使用KVC修改属性变量,KVO依然会触发,所以KVC内部应该也调用了willChangeValueForKey:key 和 didChangeValueForKey:key 方法,从而触发了KVO。
<2>KVC的赋值和取值过程是怎样的?原理是什么?
如上原理图所示