是否可以使用KVO,不仅可以检测值是否更改,还可以检测是否再次设置了相同的值?我目前只在值发生变化时收到通知(与之前设置的值不同)。我需要在每次设置值时接收通知(即使它与先前设置的相同)。我怎样才能做到这一点?
我的代码:
private func addObserver() {
defaults.addObserver(self, forKeyPath: DefaultsKeys.testKey._key, options: .new, context: nil)
}
public override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
guard let value = change?[NSKeyValueChangeKey.newKey] as? Bool else { return }
statusCallback?(value)
}
private func removeObserver() {
defaults.removeObserver(self, forKeyPath: DefaultsKeys.testKey._key)
}
每次设置被观察的属性时,通常会调用KVO,即使它与上次的值相同。但是我想你正在观察UserDefaults
,它有一个特性阻止这种情况发生(可能是一个优化,可以防止不必要的存储保存)。
您可以注册.didChangeNotification
,它似乎调用了值是否更改:
NotificationCenter.default.addObserver(forName: UserDefaults.didChangeNotification, object: nil, queue: .main) { notification in
print("notification", notification)
}
您可以通过以下方式实现此目的:
public override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
let value = change?[.oldKey] as? Bool
guard value == nil || value != yourVariableToCheck else { return }
statusCallback?(value)
}
只更改您自己变量的yourVariableToCheck。
KVO机制非常简单 - 它在设置新值时不执行任何额外检查,仅在调用setter时触发。因此,如果该值与已经设置的值不同,则不可能区分。这很好。首先,因为在实践中将相同的值分配给变量并不常见。 其次,引入额外的检查将是消耗品,并且在大多数情况下是不需要的。如果存在该检查,则会对性能产生负面影响。
话虽如此,就Swift而言,您可以考虑用原生Swift属性观察者替换KVO机制(实质上是Objective-C遗产):willSet
和didSet
。这基本上与通过两个选项扮演相同的角色:NSKeyValueObservingOptionNew
和NSKeyValueObservingOptionOld
(在Swift中的.old
和.new
)到addObserver
方法。一旦指定了这些标志,每当触发KVO机制时,您将在observeValue(...)
中接收这两个值(旧的和新的),您可以从中决定如何处理这两个值。但是,当willSet
几乎完全相同并且更加稳定时,为什么你需要这样的复杂性:
var myVariable : String! {
willSet {
print("Old value is: \(myVariable)")
print("New value is: \(newValue)")
// Let's do something with our old value
}
didSet {
print("Just set the new value: \(newValue)")
// New value is set. Let's do some actions.
}
}
如果你想在NSUserDefaults
中跟踪每个设置值,即使新值与之前的值相同,也要用NSDictionary
包装该值,并在字典中放入NSUUID
值,每次调用时都会生成一个新的setValue
。
之前(observeValueForKeyPath
没有呼吁每个setValue
):
[self.mySharedDefaults setValue: @"CHECKING" forKey:@"appStatusOUT"];
之后(observeValueForKeyPath
被称为每个setValue
):
[self.mySharedDefaults setValue: [NSDictionary dictionaryWithObjectsAndKeys: @"CHECKING", @"CMD",
[NSUUID UUID].UUIDString, @"UUID", nil] forKey:@"appStatusOUT"];