iOS KVO 补充版

2020-06-19  本文已影响0人  飞不越疯人院

1. 什么是KVO?

  1. KVO全称key-value observing;
  2. KVOOC观察者设计模式的又一个实现;
  3. APPLE使用isa-swizling混写技术实现KVO;

2. KVO实现流程(本质)?

KVO的大致流程
  1. Object调用addObserver:<#(nonnull NSObject *)#> forKeyPath:<#(nonnull NSString *)#> options:<#(NSKeyValueObservingOptions)#> context:<#(nullable void *)#>方法添加监听者;
  2. 系统利用runtime动态创建NSNotifying_Object类, 并将原来Obejct类的isa指针重新指向新创建的NSNotifying_Object (实例对象的isa指向类对象);

isa混写技术在KVO中是如何应用的?
isa指针修改进行重新指向的过程就是isa混写技术在KVO中的应用;

  1. 当修改实例对象的属性值时, 触发Foundation框架中的NSSetXXXXValueAndNotify函数;
  2. 调用willChangeValueForKey方法;
  3. 父类原先的setter方法;
  4. 调用didChangeValueForKey方法;
  5. 触发observeValueForKeyPath: ofObject: change: context:方法;
补充
///KVO内部实现如下(伪代码)
NSSetLongLongValueAndNotify方法的内部实现 {
    [self willChangeValueForKey:@"keyPath"];
    ///调用父类实现
    [super setCount:count];
    ///此方法触发监听的实现方法observeValueForKeyPath....
    [self didChangeValueForKey:@"keyPath"];
}

3. 触发KVO的方式?

  1. 通过setter方法赋值;
  2. 通过KVC赋值;
  3. 通过成员变量赋值+手动触发;
///单纯的成员变量赋值, 无法触发KVO
- (void)increaseCount1 {
    _count ++;
}

///成员变量赋值+手动触发KVO
- (void)increaseCount2 {
    ///通过这两个方法可以手动触发KVO
    [self willChangeValueForKey:@"count"];
    _count ++;
    [self didChangeValueForKey:@"count"];
}
  1. 手动触发 KVO, 调用方法willChangeValueForKeydidChangeValueForKey;
///测试代码如下:
@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;


示例代码


有理解错误地方请不吝赐教

上一篇 下一篇

猜你喜欢

热点阅读