iOS KVO - 检测何时再次设置相同的值

时间:2017-10-22 12:21:35

标签: ios swift nsuserdefaults key-value-observing userdefaults

是否可以使用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)
}

4 个答案:

答案 0 :(得分:2)

每次设置被观察的属性时,KVO通常 调用,即使它与上次的值相同。但是我想你正在观察UserDefaults,并且它有一个特性可以防止这种情况发生(可能是一种优化,可以防止不必要的商店保存)。

您可以注册.didChangeNotification,这似乎是调用值是否已更改:

NotificationCenter.default.addObserver(forName: UserDefaults.didChangeNotification, object: nil, queue: .main) { notification in
    print("notification", notification)
}

答案 1 :(得分:0)

您可以通过以下方式实现此目的:

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

答案 2 :(得分:0)

KVO机制非常简单 - 它在设置新值时不执行任何额外检查,仅在调用setter时触发。因此,如果该值与已经设置的值不同,则不可能区分。 这很好。首先,因为在实践中为变量赋予相同的值并不常见 其次,引入额外的检查将是消耗品,并且在大多数情况下是不需要的。如果检查存在,则会对性能产生负面影响。

话虽如此,就Swift而言,您可以考虑使用本机Swift属性观察器替换KVO机制(实质上是Objective-C遗留):willSetdidSet。这基本上与将两个选项:NSKeyValueObservingOptionNewNSKeyValueObservingOptionOld(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.
    }
}

答案 3 :(得分:0)

如果要跟踪NSUserDefaults中的每个设置,即使新值与以前的值相同,也请用NSDictionary包裹该值,然后将{{1 }}值,每次调用新的NSUUID时都会生成。

之前({setValue并未在每个observeValueForKeyPath上调用):

setValue

(每[self.mySharedDefaults setValue: @"CHECKING" forKey:@"appStatusOUT"]; 被调用observeValueForKeyPath之后):

setValue