Swift 中可以使用键值观察 (KVO) 吗?
在 Swift 中,您可以使用 KVO 通过为该属性注册观察者来观察对象属性的更改。当属性值更改时,会通知观察者,并可以采取适当的操作。在本文中,您将看到如何在 Swift 中实现 KVO 的示例。
要在 Swift 中使用 KVO,您需要执行以下操作
使用 @objc dynamic 属性标记要观察的属性。此属性告诉 Swift 编译器为该属性生成与 Objective-C 兼容的代码。
使用被观察对象的 addObserver(_:forKeyPath:options:context:) 方法注册该属性的观察者。
在观察者中实现 observeValue(forKeyPath:of:change:context:) 方法以处理对被观察属性的更改。
addObserver(_:forKeyPath:options:context:) 方法
addObserver(_:forKeyPath:options:context:) 方法用于为对象的特定键路径添加观察者。它采用以下参数:
observer - 观察键路径的对象。
keyPath - 指定要观察的键路径的字符串。
options - 确定如何向观察者报告键路径更改的选项数组。
context - 当通知观察者更改时传递给观察者的上下文对象。
options 参数是一个选项数组,用于确定如何将对被观察键路径的更改报告给观察者。可用的选项包括:
.old - 在报告更改时,在更改字典中包含属性的旧值。
.new - 在报告更改时,在更改字典中包含属性的新值。
.initial - 在添加观察者时报告属性的初始值。
.prior - 在报告更改时,在更改字典中包含属性的上一个值。
context 参数是任意上下文对象,当通知观察者更改时传递给观察者。这可用于向观察者提供其他信息。
removeObserver(_:forKeyPath:) 方法
removeObserver(_:forKeyPath:) 方法用于删除对象的特定键路径的观察者。它采用以下参数:
observer - 观察键路径的对象。
keyPath - 指定停止观察的键路径的字符串。
当不再需要观察者时,必须将其移除。这是为了避免内存泄漏并防止观察者在其被释放后接收通知。
@objc dynamic
@objc dynamic 是 Swift 语言属性,用于使类的属性在 Objective-C 中可以通过键值观察 (KVO) 进行观察。KVO 是一种允许对象观察另一个对象属性的更改的机制。
@objc 属性用于将 Swift 类或其成员公开给 Objective-C,以便 Objective-C 代码可以使用它们。dynamic 属性用于告诉编译器对属性或方法使用动态调度而不是静态调度。这意味着属性或方法可以在运行时被重写。
为了使属性可以通过 KVO 进行观察,它必须同时使用 @objc 和 dynamic 进行标记。当属性使用 @objc dynamic 标记时,编译器会生成其他代码,从而为该属性启用 KVO。这包括创建一个新的动态子类,该子类重写属性的 getter 和 setter 方法,以便在属性值更改时通知注册的观察者。
示例
import Foundation class Person: NSObject { // Declare the property that you want to observe as @objc dynamic in the class where it is defined. @objc dynamic var name: String = "" } // Define a new observer class that inherits from NSObject. class PersonObserver: NSObject { var person: Person init(person: Person) { self.person = person super.init() person.addObserver(self, forKeyPath: #keyPath(Person.name), options: [.old, .new], context: nil) } deinit { person.removeObserver(self, forKeyPath: #keyPath(Person.name)) } override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) { guard keyPath == #keyPath(Person.name), let newValue = change?[.newKey] as? String, let oldValue = change?[.oldKey] as? String else { return } print("Property '\(keyPath!)' changed from '\(oldValue)' to '\(newValue)'") } } // Create an instance of Person and an instance of PersonObserver. let alex = Person() let observer = PersonObserver(person: alex) // Change the value of the name on alex alex.name = "Alex" alex.name = "Alex Murphy"
输出
Property 'name' changed from '' to 'Alex' Property 'name' changed from 'Alex' to 'Alex Murphy'
在此示例中,Person 是被观察的对象,PersonObserver 是观察者。Person 的 name 属性使用 @objc dynamic 属性进行标记以启用 KVO。观察者为 alex 的 name 属性注册,并实现 observeValue(forKeyPath:of:change:context:) 方法以处理对该属性的更改。当属性值更改时,会调用观察者的方法实现,并传入更改后的值。
结论
总之,@objc dynamic 是 Swift 语言属性,用于使类的属性在 Objective-C 中可以通过键值观察 (KVO) 进行观察。为了使属性可以通过 KVO 进行观察,必须同时使用 @objc 和 dynamic 进行标记。当属性使用 @objc dynamic 标记时,编译器会生成其他代码,从而为该属性启用 KVO。建议仅在属性需要在 Objective-C 中通过 KVO 进行观察时才使用 @objc dynamic,因为不必要地使用它可能会影响性能。