为什么 User Defaults publisher 会触发多次
Why does User Defaults publisher trigger multiple times
我正在订阅内置的用户默认扩展,但它似乎不必要地触发了多次。
这是我使用的代码:
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: \([=10=])") }
.store(in: &cancellable)
defaults.someProperty = true
cancellable.removeAll()
PlaygroundPage.current.needsIndefiniteExecution = true
这会打印:
Before: false
Sink: false
Sink: true
Sink: true
为什么发射接收器 3 次而不是一次?
我也许可以理解它在订阅时触发,这令人困惑,因为它似乎不是 PassthroughSubject
或任何相关文档。然而,真正让我感到困惑的是它第三次触发。
更新:
这很奇怪,但似乎初始值被纳入 new/old 比较:
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: \([=12=])") }
.store(in: &cancellable)
defaults.someProperty = true
上面会打印哪个看起来不错:
Initial: true
Sink: true
但是当初始值与您设置的不同时:
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: \([=14=])") }
.store(in: &cancellable)
defaults.someProperty = true
上面会奇怪地打印:
Initial: false
Sink: true
Sink: true
这是不合理的,因为它将初始值视为 [.new]
的触发器,然后再次比较设置的值。
第一次发布的值是订阅时的初始值,如果不想收到初始值可以在选项中指定(它们是NSKeyValueObservingOptions
):
defaults
.publisher(for: \.someProperty, options: [.new])
.sink { print("Sink: \([=10=])") }
.store(in: &cancellable)
每个新值确实发布了两次,但您可以删除重复值:
defaults
.publisher(for: \.someProperty, options: [.new])
.removeDuplicates()
.sink { print("Sink: \([=11=])") }
.store(in: &cancellable)
这会给你想要的行为。
更新:
如果您这样定义扩展:
extension UserDefaults {
@objc var someProperty: Bool {
bool(forKey: "someProperty")
}
}
然后使用以下方法设置值:
defaults.set(false, forKey: "someProperty")
值只发布一次。
我正在订阅内置的用户默认扩展,但它似乎不必要地触发了多次。
这是我使用的代码:
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: \([=10=])") }
.store(in: &cancellable)
defaults.someProperty = true
cancellable.removeAll()
PlaygroundPage.current.needsIndefiniteExecution = true
这会打印:
Before: false
Sink: false
Sink: true
Sink: true
为什么发射接收器 3 次而不是一次?
我也许可以理解它在订阅时触发,这令人困惑,因为它似乎不是 PassthroughSubject
或任何相关文档。然而,真正让我感到困惑的是它第三次触发。
更新:
这很奇怪,但似乎初始值被纳入 new/old 比较:
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: \([=12=])") }
.store(in: &cancellable)
defaults.someProperty = true
上面会打印哪个看起来不错:
Initial: true
Sink: true
但是当初始值与您设置的不同时:
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: \([=14=])") }
.store(in: &cancellable)
defaults.someProperty = true
上面会奇怪地打印:
Initial: false
Sink: true
Sink: true
这是不合理的,因为它将初始值视为 [.new]
的触发器,然后再次比较设置的值。
第一次发布的值是订阅时的初始值,如果不想收到初始值可以在选项中指定(它们是NSKeyValueObservingOptions
):
defaults
.publisher(for: \.someProperty, options: [.new])
.sink { print("Sink: \([=10=])") }
.store(in: &cancellable)
每个新值确实发布了两次,但您可以删除重复值:
defaults
.publisher(for: \.someProperty, options: [.new])
.removeDuplicates()
.sink { print("Sink: \([=11=])") }
.store(in: &cancellable)
这会给你想要的行为。
更新:
如果您这样定义扩展:
extension UserDefaults {
@objc var someProperty: Bool {
bool(forKey: "someProperty")
}
}
然后使用以下方法设置值:
defaults.set(false, forKey: "someProperty")
值只发布一次。