gpt4 book ai didi

swift - MacOS使用KVO执行多次执行

转载 作者:行者123 更新时间:2023-11-30 12:09:57 29 4
gpt4 key购买 nike

class ViewController: NSViewController {
override func viewDidLoad() {
super.viewDidLoad()
print("in viewDidLoad");
// addObserver keyPath
UserDefaults.standard.addObserver(self, forKeyPath: "testKey", options: .new, context: nil);

print("out viewDidLoad");
}

deinit {
// removeObserver keyPath
UserDefaults.standard.removeObserver(self, forKeyPath: "testKey");
}

override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
print("in observeValue keyPath: \(keyPath) value: \(UserDefaults.standard.integer(forKey: "testKey"))");
// 1. If I execute the func click () method, it will be executed two times
// 2. If App originally existed "testKey", then func observeValue () will be executed after the viewDidLoad is finished.
}

@IBAction func click(_ sender: NSButton) {
UserDefaults.standard.set(arc4random(), forKey: "testKey");
}
}

以上代码是我的全部测试代码。我在自己的项目中使用了KVO,但发现重复执行。

//1.如果我执行func click()方法,就会执行两次

//2、如果App本来就存在“testKey”,则viewDidLoad完成后会执行funcobserveValue()。

这不是我对 KVO 的理解。我的想法是,在 addObserver 之后,如果我的 key 发生更改,我的observeValue 将被调用。但事实并非如此。我试图在论坛上寻找答案,但没有找到答案。我刚刚发现了一个类似的问题。

如果我在 View 中按下按钮,那么最终结果将是..:

in viewDidLoad
out viewDidLoad
in observeValue keyPath: Optional("testKey") value: 4112410111
in observeValue keyPath: Optional("testKey") value: 3712484288
in observeValue keyPath: Optional("testKey") value: 3712484288

macOS: 10.12.6 (16G29)xcode: 9 beta6、xcode 8.3.3

如果您也有同样的问题,请告诉更多的人来帮助我们解决。谢谢

我已经向官方发送了同样的问题,如果有解决方案,我会在这里返回。

最佳答案

从在 observeValue() 中设置断点并查看跟踪来看,观察结果似乎在两个地方被触发;一个在 click() 期间,作为告诉 UserDefaults 设置值的行的效果,另一个稍后安排在运行循环上,因此它发生在 当系统检测到值发生变化时,>click() 已经返回。这种双重通知可能被认为是一个错误,因为后一个通知应该使前一个通知变得不必要,我会考虑提交 radar report就在上面。

不幸的是,我看不到任何方法来禁用此行为。我可以想出一个解决方法,但它非常hacky、kludgey、丑陋,而且除非需求绝对迫切,否则我可能不会真正这样做。但它是:

private var kvoContext = 0

private let ignoreKVOKey = "com.charlessoft.example.IgnoreKVO"

// If this can be called from a thread other than the main thread,
// then you will need to take measures to protect it against race conditions
private var shouldIgnoreKVO = false

override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
if context == &self.kvoContext { // always, always use a context pointer
if !shouldIgnoreKVO { // if this is a notification we don't want, ignore it
print("in observeValue keyPath: \(String(describing: keyPath)) value: \(UserDefaults.standard.integer(forKey: "testKey"))");
}
} else {
// call super if context pointer doesn't match ours
super.observeValue(forKeyPath: keyPath, of: object, change: change, context: context)
}
}

@IBAction func click(_ sender: NSButton) {
// we don't need this notification, since we'll get the later one
// resulting from the defaults having changed
self.shouldIgnoreKVO = true
defer { self.shouldIgnoreKVO = false }

UserDefaults.standard.set(arc4random(), forKey: "testKey");
}

再说一次,它很丑陋,很老套,我可能实际上不会这样做。但它就在那里。

关于swift - MacOS使用KVO执行多次执行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46203872/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com