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

问题描述 投票:1回答:4

是否可以使用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)
}
ios swift nsuserdefaults key-value-observing userdefaults
4个回答
2
投票

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

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

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

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。


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.
    }
}

0
投票

如果你想在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"];
© www.soinside.com 2019 - 2024. All rights reserved.