KVO陷阱

作者: 凯旋之歌 | 来源:发表于2018-08-05 17:17 被阅读0次

          KVO,全称为Key-Value Observing,是iOS中的一种设计模式,用于检测对象的某些属性的实时变化情况并作出响应。网上广为流传普及的一个例子是利用KVO检测股票价格的变动,例如这里。这个例子作为扫盲入门还是可以的,但是当应用场景比较复杂时,里面的一些细节还是需要改进的,里面有多个地方存在crash的危险。本文旨在逐步递进深入地探讨出一种目前比较健壮稳定的KVO实现方案,弥补网上大部分教程的不足!

首先,假设我们的目标是在一个UITableViewController内对tableview的contentOffset进行实时监测,很容易地使用KVO来实现为。

在初始化方法中加入:

[_tableView addObserver:self forKeyPath:@"contentOffset" options:NSKeyValueObservingOptionNew context:nil];

在dealloc中移除KVO监听:

[_tableView removeObserver:self forKeyPath:@"contentOffset" context:nil];

添加默认的响应回调方法:

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object

                        change:(NSDictionary *)change context:(void *)context

{

      [self doSomethingWhenContentOffsetChanges];

}

好了,KVO实现就到此完美结束了,拜拜。。。开个玩笑,肯定没这么简单的,这样的代码太粗糙了,当你在controller中添加多个KVO时,所有的回调都是走同上述函数,那就必须对触发回调函数的来源进行判断。判断如下:

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object

                        change:(NSDictionary *)change context:(void *)context

{

    if (object == _tableView && [keyPath isEqualToString:@"contentOffset"]) {

      [self doSomethingWhenContentOffsetChanges];

} }

你以为这样就结束了吗?答案是否定的!我们假设当前类(在例子中为UITableViewController)还有父类,并且父类也有自己绑定了一些其他KVO呢?我们看到,上述回调函数体中只有一个判断,如果这个if不成立,这次KVO事件的触发就会到此中断了。但事实上,若当前类无法捕捉到这个KVO,那很有可能是在他的superClass,或者super-superClass...中,上述处理砍断了这个链。合理的处理方式应该是这样的:

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object

                        change:(NSDictionary *)change context:(void *)context

{

    if (object == _tableView && [keyPath isEqualToString:@"contentOffset"]) {

        [self doSomethingWhenContentOffsetChanges];

} else {

        [super observeValueForKeyPath:keyPath ofObject:object change:change context:context];

}

}

这样就结束了吗?答案仍旧是否定的。潜在的问题有可能出现在dealloc中对KVO的注销上。KVO的一种缺陷(其实不能称为缺陷,应该称为特性)是,当对同一个keypath进行两次removeObserver时会导致程序crash,这种情况常常出现在父类有一个kvo,父类在dealloc中remove了一次,子类又remove了一次的情况下。不要以为这种情况很少出现!当你封装framework开源给别人用或者多人协作开发时是有可能出现的,而且这种crash很难发现。不知道你发现没,目前的代码中context字段都是nil,那能否利用该字段来标识出到底kvo是superClass注册的,还是self注册的?

回答是可以的。我们可以分别在父类以及本类中定义各自的context字符串,比如在本类中定义context为@"ThisIsMyKVOContextNotSuper";然后在dealloc中remove observer时指定移除的自身添加的observer。这样iOS就能知道移除的是自己的kvo,而不是父类中的kvo,避免二次remove造成crash。

综上所述:需要做的是:

1.在本类添加:staticNSString*ctxKVOOfMTMaterialManagerVC =@"ctxKVOOfMTMaterialManagerVC";


2.dealloc里添加:(写在前面避免遗漏忘记)

@try {

        [self removeObserver:self

                  forKeyPath:NSStringFromSelector(@selector(selectedMaterials))

                     context:&ctxKVOOfMTMaterialManagerVC];

    }

    @catch(NSException *__unusedexception) {

       NSLog(@"try removeObserver:%@ crash",self.class);

    }


3.需要的地方进行观察:

[self addObserver:self

           forKeyPath:NSStringFromSelector(@selector(selectedMaterials))

              options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionInitial

              context:&ctxKVOOfMTMaterialManagerVC];


4.响应处理:

- (void)observeValueForKeyPath:(NSString*)keyPath ofObject:(id)object change:(NSDictionary*)change context:(void*)context {

    if (context == &ctxKVOOfMTMaterialManagerVC) {

        xxx

    }else{               [superobserveValueForKeyPath:keyPathofObject:objectchange:changecontext:context];

    }

}


KVO陷阱

相关文章

  • KVO陷阱

    KVO,全称为Key-Value Observing,是iOS中的一种设计模式,用于检测对象的某些属性的...

  • KVO陷阱

    引用:http://www.cnblogs.com/wengzilin/p/4346775.html 解决办法:可...

  • iOS下KVO使用过程中的陷阱KVO,

    【原】iOS下KVO使用过程中的陷阱KVO,全称为Key-Value Observing,是iOS中的一种设计模式...

  • iOS下KVO使用过程中的陷阱

    面试中被问到KVO下常见的crash原因。转载了一下KVO使用陷阱 鉴于我自己对这块没有太多的认知。通过博主文章加...

  • iOS原理篇(一): KVO实现原理

    KVO实现原理 什么是 KVO KVO 基本使用 KVO 的本质 总结 一 、 什么是KVO KVO(Key-Va...

  • 04. KVO使用,原理,本质

    问题 KVO日常使用 KVO原理(KVO本质是什么) 如何手动触发KVO 直接修改成员变量会触发KVO吗 KVO图...

  • 20.iOS底层学习之KVO 原理

    本篇提纲1、KVO简介;2、KVO的使用;3、KVO的一些细节;4、KVO的底层原理; KVO简介 KVO全称Ke...

  • 深入理解KVO

    iOS | KVO | Objective-C KVO的本质是什么,如何手动触发KVO? 1.什么是KVO KVO...

  • OC语法:KVO的底层实现

    一、KVO是什么二、怎么使用KVO三、KVO的底层实现四、KVO常见面试题 一、KVO是什么 KVO全称Key-V...

  • KVO基本使用

    分三部分解释KVO一.KVO基本使用二.KVO原理解析三.自定义实现KVO 一、KVO基本使用 使用KVO,能够非...

网友评论

      本文标题:KVO陷阱

      本文链接:https://www.haomeiwen.com/subject/vwwbvftx.html