前言

在开发中我们经常需要用到KVO,但KVO一旦使用不当,会造成致命性的问题-崩溃。

在开发中KVO尝试过很多方法来使用KVO,有init方法中添加,dealloc方法中移除,如果有问题,在搞个布尔值标记下,网上很多方法在使用中可能场景和需求不一样,效果不保险感觉。

方案

今天偶尔看到MJRefresh框架在对KVO的处理,通过了解并Demo演练,发现这种方法非常不错,故此推荐给大家。

1
- (void)willMoveToSuperview:(UIView *)newSuperview;

这是系统的方法,当视图将要添加到父视图上,或将要从父视图上移除时会调用。在这个方法处理监听的添加和移除。Demo下载
先上代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
- (void)willMoveToSuperview:(UIView *)newSuperview
{
[super willMoveToSuperview:newSuperview];

NSLog(@"%s",__func__);

[self removeObserver];

if(newSuperview) {
if([newSuperview isKindOfClass:[ObserverView class]]) {
_obView = (ObserverView *)newSuperview;

[self addObserver];
}
}
}

- (void)addObserver
{
NSLog(@"%s",__func__);

NSKeyValueObservingOptions options = NSKeyValueObservingOptionNew;
[self.obView addObserver:self forKeyPath:@"clickCount" options:(options) context:nil];
}

- (void)removeObserver
{
NSLog(@"%s",__func__);

NSLog(@"%@ -- %@",self.obView,self.superview);

/**
! 切记 这里必须用self.superview
self.obView 在这个时候已经是nill
*/
// [self.obView removeObserver:self forKeyPath:@"clickCount"];
[self.superview removeObserver:self forKeyPath:@"clickCount"];
}

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context
{
if([keyPath isEqualToString:@"clickCount"]) {
self.textlabel.text = [NSString stringWithFormat:@"%ld",self.obView.clickCount];

}
}

总结和注意点:

1
2
3
4
5
6
7
总结和注意点:
可在willMoveToSuperview: 添加和移除监听者

1. 需要调用super willMoveToSuperview
2. 需要先移除 监听者 removeObserver
3. 然后在willMoveToSuperview 参数 newSuperview 有值 设置监听者 addObserver
4. removeObserver 内如果是监听的父类,在这里必须写self.super 因为自己设置的属性指向父类,在这里属性是没值的