相信大家对于KVO的使用应该不会存在什么疑问,addObserver:forKeyPath:options:context:与removeObserver:forKeyPath:context:必须成对出现。
按照官方文档中描述,Observer(观察者)在被释放时是不会自动移除的,被观察的对象会继续发送通知而是不会去检查 Observer(观察者)的状态的,当发送给一个被释放的 Observer(观察者)时内存就会出现异常。所以由此可以推断 Observer(观察者)在调用addObserver:forKeyPath:options:context:注册时不是被强引用的。
按照官方文档中描述,Observer(观察者)通常情况下是在init或者viewDidLoad时注册,在dealloc时移除。
所以在UIView我们会经常在init进行注册,在dealloc时进行注册。这本身没有问题,因为苹果官方文档也这么说的,但是总是感觉有点不好,能不能像UIViewController那样,通过生命周期的相关接口进行注册和取消呢?
负责UIView的生命周期的接口有:
UIView生命周期如下:
未添加subView:
push:willMoveToSuperview->didMoveToSuperview->willMoveToWindow->didMoveToWindow->layoutSubviews
pop:->willMoveToWindow->didMoveToWindow->willMoveToSuperview->didMoveToSuperview->removeFromSuperview->dealloc
添加subView:
push:willMoveToSuperview->didMoveToSuperview->willMoveToWindow->didMoveToWindow->layoutSubviews->didAddSubview->layoutSubviews
pop:->willMoveToWindow->didMoveToWindow->willMoveToSuperview->didMoveToSuperview->removeFromSuperview->dealloc->willRemoveSubview
如果在UIView中实现subView的KVO,那么可以在didAddSubview中注册,在willRemoveSubview中取消。
如果在UIView中实现自己的KVO,找到眼瞎也没有找到removeFromSuperview等字眼,真是失望透顶,但是大家有没有发现,在UIView生命周期中MoveToSuperview、MoveToWindow在push和pop都调用了,其中的奥秘就在参数:superview,当push时,是将UIView添加到superview,所以参数superview是不为nil的。当pop时,是将UIView从superview中移除,所以参数superview是nil。
正确的姿势:
参考:
https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/KeyValueObserving/Articles/KVOBasics.html#//apple_ref/doc/uid/20002252-178612