KVC的本质就是 (键值编码)
定义: 在对象创建完成之后,动态(牵扯到运行时)的给对象的属性赋值
KVC,即是指 NSKeyValueCoding,一个非正式的Protocol,提供一种机制来间接访问对象的属性。而不是通过调用Setter、Getter方法访问。
KVO 的本质就是(键值监听)
定义::Key-Value Observing,它提供一种机制,当指定的对象的属性被修改后,则对象就会接受到通知。
KVO是基于runtime机制实现的
当某个类的属性对象第一次被观察时,系统就会在运行期动态地创建该类的一个派生类,在这个派生类中重写基类中任何被观察属性的setter方法。派生类在被重写的setter方法内实现真正的通知机制
如果原类为Person,那么生成的派生类名为NSKVONotifying_Person
每个类对象中都有一个isa指针指向当前类,当一个类对象的第一次被观察,那么系统会偷偷将isa指针指向动态生成的派生类,从而在给被监控属性赋值时执行的是派生类的setter方法
键值观察通知依赖于NSObject 的两个方法: willChangeValueForKey: 和didChangevlueForKey:;在一个被观察属性发生改变之前, willChangeValueForKey: 一定会被调用,这就 会记录旧的值。而当改变发生后,didChangeValueForKey:会被调用,继而 observeValueForKey:ofObject:change:context: 也会被调用。
补充:KVO的这套实现机制中苹果还偷偷重写了class方法,让我们误认为还是使用的当前类,从而达到隐藏生成的派生类创建一个具有这三个属性的Person类 (.h)
@interface LYPerson : NSObject
@property(nonatomic,copy)NSString *name;
@property(nonatomic,assign)CGFloat height;
@property(nonatomic,assign)NSInteger age;
@interface ViewController ()
@property(nonatomic,strong)LYPerson *person;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
LYPerson *person = [[LYPerson alloc]init];
person.height = 180;
person.name =@"交警队李哥";
person.age = 18;
self.person = person;
//KVO 大哥登场 设置监听
//注意 KeyPath 与 Key 虽然都是通过键去找值但 KeyPath 会自动寻址
//比如说我 height 属性里还有一个"躺下的高度"或"站着的高度"(哈哈还 太污了)
//通过 KeyPath 就会层层深入找到 Key 就只能找 height 这一层
//NSKeyValueObservingOptionOld 属性的旧值
//NSKeyValueObservingOptionNew 属性的新值
//context 携带的参数
[person addObserver:self forKeyPath:@"height" options:NSKeyValueObservingOptionOld | NSKeyValueObservingOptionNew context:nil];
//我要改值了
person.height = 181;
}
//keyPath
//object 被修改属性的类的对象
//change 返回改变前后的属性与属性值(字典)
//context 携带的参数
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary*)change context:(void *)context{
NSLog(@"%@",change);
}
这里指的是“person的isa指针变了”
细心机制的你早已发现 NSObject 里的 isa指针 改变了
指向了一个看着眼熟似曾相识的类 没错! 那个就是系统帮我们创建的子类