iOS KVO 补充版
2020-06-19 本文已影响0人
飞不越疯人院
1. 什么是KVO?
-
KVO
全称key-value observing
; -
KVO
是OC
中观察者设计模式的
又一个实现; -
APPLE
使用isa-swizling
混写技术实现KVO
;
2. KVO实现流程(本质)?

-
Object
调用addObserver:<#(nonnull NSObject *)#> forKeyPath:<#(nonnull NSString *)#> options:<#(NSKeyValueObservingOptions)#> context:<#(nullable void *)#>
方法添加监听者; - 系统利用
runtime
动态创建NSNotifying_Object
类, 并将原来Obejct
类的isa
指针重新指向新创建的NSNotifying_Object
(实例对象的isa
指向类对象);
isa
混写技术在KVO
中是如何应用的?
将isa
指针修改进行重新指向的过程就是isa
混写技术在KVO
中的应用;
- 当修改实例对象的属性值时, 触发
Foundation
框架中的NSSetXXXXValueAndNotify
函数; - 调用
willChangeValueForKey
方法; - 父类原先的
setter
方法; - 调用
didChangeValueForKey
方法; - 触发
observeValueForKeyPath: ofObject: change: context:
方法;
补充
- 添加
KVO
后setter
的实现是有被Foundation_NSSetLongLongValueAndNotify
方法替换;验证如下图所示:
///KVO内部实现如下(伪代码)
NSSetLongLongValueAndNotify方法的内部实现 {
[self willChangeValueForKey:@"keyPath"];
///调用父类实现
[super setCount:count];
///此方法触发监听的实现方法observeValueForKeyPath....
[self didChangeValueForKey:@"keyPath"];
}

-
NSNotifying_Object
的 替换验证如下图:
第一个断点处, obj类型是AObject
第二个断点处, obj类型是NSNotifying_AObject
3. 触发KVO的方式?
- 通过
setter
方法赋值; - 通过
KVC
赋值; - 通过成员变量赋值+手动触发;
///单纯的成员变量赋值, 无法触发KVO
- (void)increaseCount1 {
_count ++;
}
///成员变量赋值+手动触发KVO
- (void)increaseCount2 {
///通过这两个方法可以手动触发KVO
[self willChangeValueForKey:@"count"];
_count ++;
[self didChangeValueForKey:@"count"];
}
- 手动触发 KVO, 调用方法
willChangeValueForKey
和didChangeValueForKey
;
///测试代码如下:
@interface ViewController ()
@property (nonatomic, assign) NSInteger number;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
[self addObserver:self forKeyPath:@"number" options:0x01 | 0x02 context:nil];
self.number = 12;
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
[self willChangeValueForKey:@"number"];
[self didChangeValueForKey:@"number"];
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context {
NSLog(@"%@____%@____%@", keyPath, object, change);
}
@end
///当点击屏幕执行那两行代码后会再次触发 KVO
2020-06-19 18:29:17.820689+0800 KVO[32945:343386] number____<ViewController: 0x7f9619506360>____{
kind = 1;
new = 12;
old = 0;
}
2020-06-19 18:29:20.986027+0800 KVO[32945:343386] number____<ViewController: 0x7f9619506360>____{
kind = 1;
new = 12;
old = 12;
}
补充
什么样的情况可以使用 KVO?
有 setter
方法的才能使用 KVO
;如果没有setter
需要使用手动触发KVO
;
有理解错误地方请不吝赐教