为什么“用户默认值"发布者会多次触发 [英] Why does User Defaults publisher trigger multiple times

查看:52
本文介绍了为什么“用户默认值"发布者会多次触发的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在订阅内置的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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆