Swift 中 KVO 用法小结


建立监听

Meler Paine
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
}
}

创建好的观察者 observationNSKeyValueObservation 类型,使用时需要将它保存在合适的作用域中,监听的周期和观察者的生命周期是一致的,如果在视图控制器中创建了一个监听,通常将观察者作为控制器的可选属性。

移除监听

在观察者所在的作用域消失时,要确保监听已被移除,移除时很简单,如果观察者是可选属性,直接置为 nil 即可,如果不是,则调用它的 invalidate() 方法。 一般情况下不需要手动移除观察者,如果观察者所在类的 deinit 方法未被调用,则观察者肯定还未被移除。原因可能有以下两种: - 监听的处理闭包中,捕获了 self,导致循环引用无法移除,需要使用 weakunowned 来处理。 - 观察者被其他对象引用了,需要手动释放观察者。

如何判断还有未移除的观察者

假设 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>
)
Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade