KVO keyPathsForValuesAffecting 不起作用
KVO keyPathsForValuesAffecting doesn't work
我对 keyPathsForValuesAffecting<key>
方法有疑问。当 name
或 surname
发生变化时,我想通知 fullName
的观察者。但不幸的是观察者没有得到通知。
我的代码:
class 将被观察到:
class DependencyTest: NSObject {
@objc dynamic var fullName: String {
return name + " " + surname
}
@objc var name = ""
@objc var surname = ""
class func keyPathsForValuesAffectingFullName() -> Set<NSObject> {
return ["name" as NSObject, "surname" as NSObject]
}
}
观察者ViewController:
let dep = DependencyTest()
override func viewDidLoad() {
super.viewDidLoad()
addObserver(self, forKeyPath: "dep.fullName", options: .prior, context: nil)
dep.name = "bob" // Im expecting that `observeValue:` method will be fired
dep.surname = "gril"
}
override func observeValue(forKeyPath keyPath: String?,
of object: Any?,
change: [NSKeyValueChangeKey : Any]?,
context: UnsafeMutableRawPointer?) {
print("" + keyPath!) // not called
}
谢谢!
这应该可以解决您的问题。
class ViewController: UIViewController {
@objc let dep = DependencyTest()
override func viewDidLoad() {
super.viewDidLoad()
self.addObserver(self, forKeyPath: #keyPath(dep.fullName), options: .new, context: nil)
self.dep.name = "bob" // Im expecting that `observeValue:` method will be fired
self.dep.surname = "gril"
}
override func viewWillDisappear(_ animated: Bool) {
self.removeObserver(self, forKeyPath: #keyPath(dep.fullName))
}
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
print("" + keyPath!) // not called
print("Full Name = ", dep.fullName)
}
}
class DependencyTest: NSObject {
@objc dynamic var fullName: String = ""
var name = "" {
didSet {
fullName = name + " " + surname
}
}
var surname = "" {
didSet {
fullName = name + " " + surname
}
}
}
作为函数的变量运行将无法观察到,您必须设置一个实际值。还要记住删除观察者,因为这不是原生的 swift 函数,它不会取消初始化,并且可以在你关闭它后将你的 VC 保存到内存中。
name
和 surname
属性也必须是 @objc dynamic
。由于您的 keyPathsForValuesAffectingFullName
方法,KVO 在观察到 fullName
时观察它们。 @objc
是观察它们所必需的。 dynamic
是使 Swift 每次设置时实际调用 setter 所必需的(这是 KVO 挂钩的),而不是内联它并仅设置支持实例变量。
您需要在 keyPathsForValuesAffecting
方法上使用 @objc
以便 KVO 机器可以使用 Objective-C 运行时找到它:
@objc class func keyPathsForValuesAffectingFullName() -> Set<NSObject> {
return ["name, "surname"]
}
顺便说一句,你可以使用 属性 代替,你可以使用 #keyPath
特殊形式让编译器帮助你捕获错误:
@objc class var keyPathsForValuesAffectingFullName: Set<String> {
return [#keyPath(name), #keyPath(surname)]
}
您还应该按照 Ken Thomases 的建议,在上游属性(name
和 surname
)上使用 dynamic
。
这是一个完整的测试程序(作为 macOS 命令行程序):
import Foundation
class DependencyTest: NSObject {
@objc dynamic var fullName: String {
return name + " " + surname
}
@objc dynamic var name = ""
@objc dynamic var surname = ""
@objc class var keyPathsForValuesAffectingFullName: Set<String> {
return [#keyPath(name), #keyPath(surname)]
}
}
class Observer: NSObject {
@objc let dep: DependencyTest
init(dep: DependencyTest) {
self.dep = dep
super.init()
addObserver(self, forKeyPath: #keyPath(Observer.dep.fullName), options: .prior, context: nil)
}
deinit {
removeObserver(self, forKeyPath: #keyPath(Observer.dep.fullName), context: nil)
}
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
print("kvo: \(keyPath!) \(change?[.notificationIsPriorKey] as? Bool ?? false ? "prior" : "post")")
}
}
let d = DependencyTest()
let o = Observer(dep: d)
d.name = "Robert"
输出:
kvo: dep.fullName prior
kvo: dep.fullName post
Program ended with exit code: 0
我对 keyPathsForValuesAffecting<key>
方法有疑问。当 name
或 surname
发生变化时,我想通知 fullName
的观察者。但不幸的是观察者没有得到通知。
我的代码:
class 将被观察到:
class DependencyTest: NSObject {
@objc dynamic var fullName: String {
return name + " " + surname
}
@objc var name = ""
@objc var surname = ""
class func keyPathsForValuesAffectingFullName() -> Set<NSObject> {
return ["name" as NSObject, "surname" as NSObject]
}
}
观察者ViewController:
let dep = DependencyTest()
override func viewDidLoad() {
super.viewDidLoad()
addObserver(self, forKeyPath: "dep.fullName", options: .prior, context: nil)
dep.name = "bob" // Im expecting that `observeValue:` method will be fired
dep.surname = "gril"
}
override func observeValue(forKeyPath keyPath: String?,
of object: Any?,
change: [NSKeyValueChangeKey : Any]?,
context: UnsafeMutableRawPointer?) {
print("" + keyPath!) // not called
}
谢谢!
这应该可以解决您的问题。
class ViewController: UIViewController {
@objc let dep = DependencyTest()
override func viewDidLoad() {
super.viewDidLoad()
self.addObserver(self, forKeyPath: #keyPath(dep.fullName), options: .new, context: nil)
self.dep.name = "bob" // Im expecting that `observeValue:` method will be fired
self.dep.surname = "gril"
}
override func viewWillDisappear(_ animated: Bool) {
self.removeObserver(self, forKeyPath: #keyPath(dep.fullName))
}
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
print("" + keyPath!) // not called
print("Full Name = ", dep.fullName)
}
}
class DependencyTest: NSObject {
@objc dynamic var fullName: String = ""
var name = "" {
didSet {
fullName = name + " " + surname
}
}
var surname = "" {
didSet {
fullName = name + " " + surname
}
}
}
作为函数的变量运行将无法观察到,您必须设置一个实际值。还要记住删除观察者,因为这不是原生的 swift 函数,它不会取消初始化,并且可以在你关闭它后将你的 VC 保存到内存中。
name
和 surname
属性也必须是 @objc dynamic
。由于您的 keyPathsForValuesAffectingFullName
方法,KVO 在观察到 fullName
时观察它们。 @objc
是观察它们所必需的。 dynamic
是使 Swift 每次设置时实际调用 setter 所必需的(这是 KVO 挂钩的),而不是内联它并仅设置支持实例变量。
您需要在 keyPathsForValuesAffecting
方法上使用 @objc
以便 KVO 机器可以使用 Objective-C 运行时找到它:
@objc class func keyPathsForValuesAffectingFullName() -> Set<NSObject> {
return ["name, "surname"]
}
顺便说一句,你可以使用 属性 代替,你可以使用 #keyPath
特殊形式让编译器帮助你捕获错误:
@objc class var keyPathsForValuesAffectingFullName: Set<String> {
return [#keyPath(name), #keyPath(surname)]
}
您还应该按照 Ken Thomases 的建议,在上游属性(name
和 surname
)上使用 dynamic
。
这是一个完整的测试程序(作为 macOS 命令行程序):
import Foundation
class DependencyTest: NSObject {
@objc dynamic var fullName: String {
return name + " " + surname
}
@objc dynamic var name = ""
@objc dynamic var surname = ""
@objc class var keyPathsForValuesAffectingFullName: Set<String> {
return [#keyPath(name), #keyPath(surname)]
}
}
class Observer: NSObject {
@objc let dep: DependencyTest
init(dep: DependencyTest) {
self.dep = dep
super.init()
addObserver(self, forKeyPath: #keyPath(Observer.dep.fullName), options: .prior, context: nil)
}
deinit {
removeObserver(self, forKeyPath: #keyPath(Observer.dep.fullName), context: nil)
}
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
print("kvo: \(keyPath!) \(change?[.notificationIsPriorKey] as? Bool ?? false ? "prior" : "post")")
}
}
let d = DependencyTest()
let o = Observer(dep: d)
d.name = "Robert"
输出:
kvo: dep.fullName prior
kvo: dep.fullName post
Program ended with exit code: 0