1

是否可以以一种不仅检测值是否更改,而且检测相同值是否再次设置的方式使用 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

4 回答 4

2

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

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

NotificationCenter.default.addObserver(forName: UserDefaults.didChangeNotification, object: nil, queue: .main) { notification in
    print("notification", notification)
}
于 2017-10-22T12:56:32.583 回答
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 。

于 2017-10-22T12:45:40.303 回答
0

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

话虽这么说,就 Swift 而言,您可以考虑用原生 Swift 属性观察器替换 KVO 机制(本质上是 Objective-C 遗留物):willSetdidSet. NSKeyValueObservingOptionNew这与将两个选项(和NSKeyValueObservingOptionOld(在 Swift 中为.old.new在 Swift 中))传递给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.
    }
}
于 2017-10-22T12:46:52.247 回答
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"];
于 2019-03-25T08:50:24.720 回答