iOS KVO - 检测何时再次设置相同的值
Posted
技术标签:
【中文标题】iOS KVO - 检测何时再次设置相同的值【英文标题】:iOS KVO - detect when the same value is set again 【发布时间】:2017-10-22 12:21:35 【问题描述】:是否可以使用 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)
【问题讨论】:
无关,如果你打算使用addObserver
,你真的应该使用context
参数来区分你的观察者和超类可能使用的任何观察者。或者使用新的 Swift 4 KVO 语法来消除这个问题。
【参考方案1】:
KVO 通常在每次设置观察到的属性时调用,即使它与上次的值相同。但我猜你正在观察UserDefaults
,它有一个特性可以防止这种情况发生(可能是一种优化,可以防止不必要的商店保存)。
您可以注册.didChangeNotification
,无论值是否改变,它似乎都会调用:
NotificationCenter.default.addObserver(forName: UserDefaults.didChangeNotification, object: nil, queue: .main) notification in
print("notification", notification)
【讨论】:
但是我如何检测到设置了特定键?我只需要监控 1 个键。 使用该通知时,我认为没有办法知道设置了哪个。您可能需要考虑UserDefaults
以外的其他内容。或者将其包装在可以触发您需要观察的东西中。【参考方案2】:
你可以这样做:
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。
【讨论】:
【参考方案3】: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.
【讨论】:
【参考方案4】:如果要跟踪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"];
【讨论】:
以上是关于iOS KVO - 检测何时再次设置相同的值的主要内容,如果未能解决你的问题,请参考以下文章
[iOS]:检测从另一个外部应用程序返回后视图控制器何时出现