返回
iOS 底层探索:自定义 KVO(四)——完善自定义 KVO
IOS
2023-10-22 22:44:12
自定义KVO(四):完善自定义 KVO
在上一篇博客中,我们已经初步实现了自定义 KVO,但还有一些问题需要解决。本篇博客将对自定义 KVO 进行完善。
解决循环引用
在自定义 KVO 的实现中,Observer
会持有被观察对象的引用,而被观察对象也会持有 Observer
的引用。这可能会导致循环引用,从而导致内存泄漏。为了解决这个问题,我们需要打破这种循环引用。
我们可以使用 WeakReference
来持有被观察对象的引用,这样当被观察对象被销毁时,Observer
不会持有它的强引用。
@implementation Observer
- (instancetype)initWithObject:(id)object keyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options changeBlock:(void (^)(id oldValue, id newValue))changeBlock {
if (self = [super init]) {
_object = object;
_keyPath = keyPath;
_options = options;
_changeBlock = changeBlock;
_weakObject = object;
}
return self;
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context {
if (_weakObject == nil) {
// 被观察对象已经被销毁,移除观察
[object removeObserver:self forKeyPath:keyPath];
return;
}
_changeBlock(change[NSKeyValueChangeOldKey], change[NSKeyValueChangeNewKey]);
}
@end
避免意外崩溃
在自定义 KVO 的实现中,如果在观察期间被观察对象被销毁,可能会导致崩溃。为了避免这种情况,我们需要在观察期间检查被观察对象是否仍然存在。
我们可以通过在观察方法中判断 _weakObject
是否为 nil
来检查被观察对象是否仍然存在。如果为 nil
,则表示被观察对象已经被销毁,我们需要移除观察并返回。
支持多层嵌套观察
自定义 KVO 还支持多层嵌套观察。这意味着我们可以观察一个对象的属性,该属性本身也是一个对象,该对象也有可以观察的属性。
为了支持多层嵌套观察,我们需要在观察方法中递归调用 observeValueForKeyPath:
方法。这样,当被观察对象的属性发生变化时,我们可以继续观察嵌套对象的属性。
自定义 KVO 的高级用法
除了基本功能外,自定义 KVO 还可以进行一些高级用法,例如:
- KVO 队列: 我们可以指定一个队列来执行 KVO 的回调。这样,我们可以控制 KVO 回调是在主线程还是其他线程执行。
- KVO 上下文: 我们可以传递一个上下文对象给 KVO 回调。这样,我们可以将其他信息传递给 KVO 回调。
- KVO 过滤: 我们可以使用
NSKeyValueObservingOptions
来过滤 KVO 回调。这样,我们可以只对特定的属性变化感兴趣。
结论
通过完善自定义 KVO 的实现,我们解决了循环引用、意外崩溃等问题,并支持了多层嵌套观察和高级用法。自定义 KVO 是一种强大的技术,可以帮助我们灵活地观察对象的属性变化,并做出相应的处理。