iOS 代理、通知、KVO
1.代理delegate
delegate 代理流程 代理方与委托方的关系2.通知NSNotification
通知 通知流程 通知实现机制3.KVO
KVO的实现依赖于 Objective-C 强大的 Runtime
,当观察某对象 A
时,KVO 机制动态创建一个对象A
当前类的子类,并为这个新的子类重写了被观察属性 keyPath
的 setter
方法。setter
方法随后负责通知观察对象属性的改变状况。
Apple 使用了 isa-swizzling
来实现 KVO 。当观察对象A
时,KVO机制动态创建一个新的名为:NSKVONotifying_A
的新类,该类继承自对象A的本类,且 KVO 为 NSKVONotifying_A
重写观察属性的setter
方法,setter
方法会负责在调用原 setter
方法之前和之后,通知所有观察对象属性值的更改情况。
NSKVONotifying_A
类剖析
NSLog(@"self->isa:%@",self->isa);
NSLog(@"self class:%@",[self class]);
在建立KVO监听前,打印结果为:
self->isa:A
self class:A
在建立KVO监听之后,打印结果为:
self->isa:NSKVONotifying_A
self class:A
在这个过程,被观察对象的 isa
指针从指向原来的 A
类,被KVO 机制修改为指向系统新创建的子类NSKVONotifying_A
类,来实现当前类属性值改变的监听;
所以当我们从应用层面上看来,完全没有意识到有新的类出现,这是系统“隐瞒”了对 KVO 的底层实现过程,让我们误以为还是原来的类。但是此时如果我们创建一个新的名为NSKVONotifying_A
的类,就会发现系统运行到注册 KVO 的那段代码时程序就崩溃,因为系统在注册监听的时候动态创建了名为 NSKVONotifying_A
的中间类,并指向这个中间类了。
子类setter方法剖析
KVO 的键值观察通知依赖于 NSObject 的两个方法:willChangeValueForKey:
和 didChangeValueForKey:
,在存取数值的前后分别调用 2 个方法:
被观察属性发生改变之前,willChangeValueForKey:
被调用,通知系统该 keyPath
的属性值即将变更;
当改变发生后, didChangeValueForKey:
被调用,通知系统该keyPath
的属性值已经变更;之后, observeValueForKey:ofObject:change:context:
也会被调用。且重写观察属性的setter 方法这种继承方式的注入是在运行时而不是编译时实现的。
KVO 为子类的观察者属性重写调用存取方法的工作原理在代码中相当于:
- (void)setName:(NSString *)newName {
[self willChangeValueForKey:@"name"]; //KVO 在调用存取方法之前总调用
[super setValue:newName forKey:@"name"]; //调用父类的存取方法
[self didChangeValueForKey:@"name"]; //KVO 在调用存取方法之后总调用
}
KVO图解及代码实现
KVO KVO原理 KVO重写了setter方法 代码1 代码2KVO可以监听到点语法、KVC,通过成员变量赋值不能被KVO监听到。
3.区别
1.代理使用代理模式,通知、KVO使用观察者模式。
2.传递方式:代理是1对1,通知是1对n。
3.KVO底层使用isa混写实现的(Runtime)。
👏👏👏欢迎大家加入群组(IT_大前端技术交流群),技术交流群
IT_大前端技术交流群