ios kvo 要引入_iOS下KVO使用过程中的陷阱

面试中被问到KVO下常见的crash原因。转载了一下KVO使用陷阱

鉴于我自己对这块没有太多的认知。通过博主文章加深理解~。本文意在探究健壮的KVO实现方案。

在初始化方法中加入:

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

执行默认回调

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

在dealloc中移除

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

我们普通写的代码可能就这样就完事了。甚至在dealloc中我们都不会进行removeObserve的操作。

事实上这样还远远不够。比如我的一个VC中有多个监听的话,这样肯定是不行的

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

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

{

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

[self doSomethingWhenContentOffsetChanges];

}

}

这样加入判断则 是哪个造成对象,然后触发响应。

但是这样还是不够的,因为可能当前类的父类也响应KVO。如果这么搞的话。KVO会在子类中断

(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];

}

}

在else的情况里面响应super的KVO.顺着响应链条去寻找。

这样仍然没有结束,潜在的问题是可能出现dealloc中KVO的注销。KVO的一种缺陷(其实不能称为缺陷,应该称为特性)是,当对同一个keypath进行两次removeObserver时会导致程序crash,这种情况常常出现在父类有一个kvo,父类在dealloc中remove了一次,子类又remove了一次的情况下。这种情况下context始终为空。 这个时候我们可以在父类在子类中的context 定义不同的名称。这样的话,可以进行区分防止removeObserve发生2次。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值