首页 > 解决方案 > 订阅发布者时无法获取最新值

问题描述

我有一个在用户登录和注销时注册/注销的侦听器。我有类似于以下代码的东西,

import Foundation
import Combine

class X : ObservableObject {
    @Published var data: String? = nil
    
    func setData() {
        data = "DATA"
    }
}

let x = X()
var store = Set<AnyCancellable>()
x.$data.sink { v1 in  // I need to add .receive(on:) here
    print(v1)
    if v1 != nil {
        x.$data.sink { v2 in
            print(v2) // Why is this nil
        }.store(in: &store)
    }
}.store(in: &store)

x.setData()

我以为v2会这样"DATA",但事实并非如此。我需要.receive(on: DispatchQueue.main)在外部订阅中做一个让他们都收到“之后”状态。

我的工作理论是,在调用所有处理程序之后不会写入值,因为我不知道如何验证它,更不用说它是否正确。

为什么receive(on:)这里有必要?

我知道我可以使用flatMap,但我没有使用它,因为我的状态传递得太晚了,我需要在退出代码运行之前取消订阅内部映射的发布者以避免权限问题。

标签: swiftcombine

解决方案


这里发生的是一种非常微妙的行为。

该表达式的x.$data计算结果为 a Published.Publisher。当您订阅 aPublished.Publisher时,它会立即发布其当前值,然后每次Published属性接收到新值时,发布者都会在新值存储到属性中之前发布新值。

此行为记录在Published参考资料中

当属性更改时,发布发生在属性的willSet块中,这意味着订阅者会在新值实际设置在属性上之前收到新值。

这意味着当您调用时x.setData(),外部订阅会在 中接收新值 ( "DATA") v1,但x.data此时仍会计算为nil。并且当您创建内部订阅时x.$data,它会立即发布其当前存储的值,该值仍然是nil.


推荐阅读