为什么“用户默认值"发布者会多次触发 [英] Why does User Defaults publisher trigger multiple times
问题描述
我正在订阅内置的User Defaults扩展名,但似乎不必要地触发了多次.
I'm subscribing the the built-in User Defaults extension, but it seems to be firing multiple times unnecessarily.
这是我正在使用的代码:
This is the code I'm using:
import Combine
import Foundation
import PlaygroundSupport
extension UserDefaults {
@objc var someProperty: Bool {
get { bool(forKey: "someProperty") }
set { set(newValue, forKey: "someProperty") }
}
}
let defaults = UserDefaults.standard
defaults.dictionaryRepresentation().keys
.forEach(defaults.removeObject)
print("Before: \(defaults.someProperty)")
var cancellable = Set<AnyCancellable>()
defaults
.publisher(for: \.someProperty)
.sink { print("Sink: \($0)") }
.store(in: &cancellable)
defaults.someProperty = true
cancellable.removeAll()
PlaygroundPage.current.needsIndefiniteExecution = true
此打印:
Before: false
Sink: false
Sink: true
Sink: true
为什么发射水槽3次而不是3次?
Why is it firing the sink 3 times instead of only once?
我也许可以理解它是在订阅时触发的,这令人困惑,因为它似乎不是 PassthroughSubject
或与此相关的任何文档.但是,真正让我困惑的是它第三次开火.
I can maybe understand it firing on subscribe, which is confusing because it doesn't seem to be a PassthroughSubject
or any documentation of this. However, what really confuses me is the third time it fires.
更新:
这很奇怪,但似乎新/旧比较中会考虑初始值:
It's strange but it seems the initial value gets factored into the new/old comparison:
defaults.someProperty = false
defaults.someProperty = true
defaults.someProperty = false
defaults.someProperty = true
print("Initial: \(defaults.someProperty)")
defaults
.publisher(for: \.someProperty, options: [.new])
.sink { print("Sink: \($0)") }
.store(in: &cancellable)
defaults.someProperty = true
以上内容将打印出来,看起来不错:
The above will print which looks good:
Initial: true
Sink: true
但是当初始值不同于您设置的初始值时:
But when the initial value is different than what you set it to:
defaults.someProperty = false
defaults.someProperty = true
defaults.someProperty = false
defaults.someProperty = true
defaults.someProperty = false
print("Initial: \(defaults.someProperty)")
defaults
.publisher(for: \.someProperty, options: [.new])
.sink { print("Sink: \($0)") }
.store(in: &cancellable)
defaults.someProperty = true
上面会奇怪地打印:
Initial: false
Sink: true
Sink: true
这是无用的,因为它将初始值视为 [.new]
的触发器,然后再次比较设置的内容.
This is untiutive because it's treating the initial value as a trigger of [.new]
, then compares again for what was set.
推荐答案
订阅时,第一个发布的值是初始值,如果您不想接收该初始值,则可以在选项中指定此值(它们是 NSKeyValueObservingOptions
):
The first published value is the initial value when you subscribe, if you don't want to receive the initial value you can specify this in options (they are NSKeyValueObservingOptions
):
defaults
.publisher(for: \.someProperty, options: [.new])
.sink { print("Sink: \($0)") }
.store(in: &cancellable)
每个新值确实都会发布两次,但是您可以删除重复项:
Every new value is indeed published twice, but you can just remove duplicates:
defaults
.publisher(for: \.someProperty, options: [.new])
.removeDuplicates()
.sink { print("Sink: \($0)") }
.store(in: &cancellable)
这会给你想要的行为.
更新:
如果您这样定义扩展名:
if you define your extension like this:
extension UserDefaults {
@objc var someProperty: Bool {
bool(forKey: "someProperty")
}
}
,然后使用以下方法设置值:
and then set the value using:
defaults.set(false, forKey: "someProperty")
这些值仅发布一次.
这篇关于为什么“用户默认值"发布者会多次触发的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!