Swift 中 KVO 用法小结
建立监听
Sep 4, 2018 · 3 min read
在 Swift 4 中对 KVO 的 api 进行了优化,比在 Objective-c 中更好用了,建立监听和监听的处理可以在一起写了:
class SomethingToObserve: NSObject {
@objc dynamic var value: Int
}
let someObject = SomethingToObserve()
observation = something.observe(\SomethingToObserve.value, options: [.new]) {
(someObject, change) in
// someObject 是被监听的对象,即前面 SomethingToObserve 初始化的实例
if let newValue = change.newValue {
// 使用变化后的值 newValue
}
}创建好的观察者 observation 是 NSKeyValueObservation 类型,使用时需要将它保存在合适的作用域中,监听的周期和观察者的生命周期是一致的,如果在视图控制器中创建了一个监听,通常将观察者作为控制器的可选属性。
移除监听
在观察者所在的作用域消失时,要确保监听已被移除,移除时很简单,如果观察者是可选属性,直接置为 nil 即可,如果不是,则调用它的 invalidate() 方法。 一般情况下不需要手动移除观察者,如果观察者所在类的 deinit 方法未被调用,则观察者肯定还未被移除。原因可能有以下两种: - 监听的处理闭包中,捕获了 self,导致循环引用无法移除,需要使用 weak 或 unowned 来处理。 - 观察者被其他对象引用了,需要手动释放观察者。
如何判断还有未移除的观察者
假设 observedValue 是被观察的属性,通过它的 observationInfo 属性可以获取它的观察者信息:
if observedValue.observationInfo != nil {
print("got observer.")
}具体有哪些观察者呢,observationInfo 是一个观察者信息的指针,指向的是 NSKeyValueObservationInfo 类型对象,其中包含了所有观察者封装类型对象 NSKeyValueObservance ,它的 Observer 属性(NSKeyValueObservation 类型)即是观察者。这两个类型都是私有类型,通过公共 api 还无法获取:
<NSKeyValueObservationInfo 0x1c44242e0> (
<NSKeyValueObservance 0x1c044b910: Observer: 0x1c48417d0, Key path: normalDictionaryDownloadProgress, Options: <New: YES, Old: NO, Prior: NO> Context: 0x0, Property: 0x1c02561d0>
<NSKeyValueObservance 0x1c4855060: Observer: 0x1c48545e0, Key path: normalDictionaryDownloadProgress, Options: <New: YES, Old: NO, Prior: NO> Context: 0x0, Property: 0x1c02561d0>
)