KVO
简介:KVO(Key-Value Observing)允许一个对象监视另一个对象特定属性的变化。当被观察对象的属性发生变化时,注册为观察者的对象会收到通知,并能够在属性变化时执行相应的操作。这种模式允许对象在不直接依赖于其他对象的情况下对其属性的变化做出响应。
人话:
对象A监听对象B,对象B的属性有改变的时候,对象A就开始执行自己的操作了,随着对象B的变化而变化。
被观察的对象需要是继承自 NSObject 的类,并且被观察的属性需要使用 @objc dynamic 进行标记,以启用 KVO。
观察者在注册时需要提供一个回调闭包,当属性变化时,观察者会收到变化的通知,可以在闭包中处理属性的变化。
KVO 是一种非常方便的模式,可以使得对象之间更加解耦,允许对象对其他对象的状态变化做出及时响应和处理。
一般应用场景:
UI 更新:在 iOS 开发中,KVO 可以用于监测数据模型的变化,并及时更新用户界面。比如,当数据模型的某个属性改变时,可以通过 KVO 更新相应的 UI 元素,确保 UI 与数据模型保持同步。
数据绑定:在 MVVM(Model-View-ViewModel)架构中,KVO 可以用于实现数据绑定,即数据模型的变化会自动更新视图层,而不需要手动管理数据与 UI 的同步。
观察对象状态:在一些情况下,你可能想要观察特定对象的状态变化,比如监测网络连接状态、设备方向的改变等。KVO 可以用于在这些状态发生变化时触发相应的操作。
数据验证与检测:KVO 可以用于监测数据的变化,并进行数据验证。比如,可以在某个属性发生变化时执行一些验证逻辑,确保数据的合法性。
自定义属性监听:除了监听系统提供的属性外,KVO 也可以用于监听自定义的属性。这对于需要在对象的自定义属性变化时进行操作的场景非常有用。
观察集合变化:KVO 不仅可以观察对象的属性变化,还可以观察集合类型(如数组和字典)的变化。这在需要监测集合中元素增删、排序变化等情况下很有用。
举例:
首先,定义一个简单的被观察对象类 Person:
import Foundation
class Person: NSObject {
@objc dynamic var name: String
init(name: String) {
self.name = name
}
}
然后,创建一个观察者类 Observer,在其中添加对 Person 类中 name 属性的观察:
class Observer: NSObject {
var person: Person
init(person: Person) {
self.person = person
super.init()
// 添加观察者
self.person.addObserver(self, forKeyPath: #keyPath(Person.name), options: [.new, .old], context: nil)
}
// 观察者方法,在属性发生变化时调用
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
if keyPath == #keyPath(Person.name), let newValue = change?[.newKey] as? String {
print("Person's name changed to: \(newValue)")
}
}
}
最后,在使用完 KVO 后,不要忘记在合适的时机取消观察:
let person = Person(name: "Alice")
let observer = Observer(person: person)
// 修改被观察对象的属性
person.name = "Bob"
// 最后,记得在合适的时候取消观察
person.removeObserver(observer, forKeyPath: #keyPath(Person.name))
注意:在使用 KVO 时,要确保合适地管理观察者和被观察对象之间的关系,以及在合适的时候取消观察,避免内存泄漏和不必要的通知。