【问题标题】:Difference between CurrentValueSubject and @PublishedCurrentValueSubject 和 @Published 之间的区别
【发布时间】:2020-02-28 18:07:58
【问题描述】:

所以我正在研究 combine 并提出了这个问题。

使用CurrentValueSubject(并使用currentValueSubject.value 设置其值)或使用@Published var 并使用$ 访问其发布者之间有什么真正的区别吗?我的意思是我知道有人返回 Subject 而不是 Publisher,但我能发现的唯一真正区别是 CurrentValueSubject 更有用,因为您可以在协议上声明它。

我真的不明白如果我们可以使用PassthroughSubject@Published 会有什么用处,我在这里遗漏了什么吗? 请注意,这是使用 UIKit,它可能对 SwiftUI 有其他用途。

谢谢。

【问题讨论】:

    标签: ios swift uikit combine


    【解决方案1】:

    CurrentValueSubject 是一个值,一个发布者和一个订阅者合而为一。

    遗憾的是,在 ObservableObject 中使用时它不会触发 objectWillChange.send()

    您可以指定错误类型。

    @Published 是一个属性包装器,因此:

    • 顶层代码尚不支持。
    • 协议声明不支持它。
    • 它只能在一个类中使用。

    @Published 在 ObservableObject 中使用时会自动触发 objectWillChange.send()

    如果您尝试从后台队列发布到 @Published 包装属性,Xcode 将发出警告。可能是因为必须从主线程调用objectWillChange.send()

    其发布者的错误类型为Never

    我对@9​​87654329@ 最大的不满是它不能充当订阅者,并且与当前值主题相比,设置组合管道需要额外的管道。

    我们可以在协议中声明@Published 属性。不是很漂亮...

    protocol TestProtocol {
        var isEnabled: Bool { get }
        var isEnabledPublished: Published<Bool> { get }
        var isEnabledPublisher: Published<Bool>.Publisher { get }
    }
    
    class Test: ObservableObject, TestProtocol {
        @Published var isEnabled: Bool = false
        var isEnabledPublished: Published<Bool> { _isEnabled }
        var isEnabledPublisher: Published<Bool>.Publisher { $isEnabled }
    }
    

    【讨论】:

    • 你不必使用@Published 你可以重新定义 var objectWillChange 成为你喜欢的任何发布者。
    【解决方案2】:

    @Published 只是一种更简洁地使用 CurrentValueSubject 的快速方法。当我调试我的一个应用程序并查看 $paramName 返回的类型时,它实际上只是一个 CurrentValueSubject:

    po self.$books
    ▿ Publisher
      ▿ subject : <CurrentValueSubject<Array<Book>, Never>: 0x6000034b8910>
    

    我想使用 CurrentValueSubject 而不是 @Published 的一个好处可能是允许您使用错误类型?

    注意:尽管我是 CurrentValueSubject现在我永远不会依赖这个假设。

    【讨论】:

    • 谢谢!另一个好处是能够在协议上声明它:)
    • @Mykod 有趣,我没有考虑过协议,是的,像 @Published 这样的包装器是不允许的:D
    • 这是可能的,但它很丑……看我的回答。
    【解决方案3】:

    我发现自己又回到了这篇文章,所以我想对@PublishedCurrentValueSubject 之间的区别添加一些额外的见解。

    可以在@Published 的文档中找到一个主要区别:

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

    此外,Swift Forums 上的对话请注意,@Published 旨在与 SwiftUI 一起使用。

    关于@Published 在其属性的willSet 块中发布,请考虑以下示例:

    class PublishedModel {
        @Published var number: Int = 0
    }
    
    let pModel = PublishedModel()
    
    pModel.$number.sink { number in
        print("Closure: \(number)")
        print("Object:  \(pModel.number) [read via closure]")
    }
    
    pModel.number = 1
    print("Object:  \(pModel.number) [read after assignment]")
    

    这会产生以下输出:

    Closure: 0
    Object:  0 [read via closure]
    Closure: 1
    Object:  0 [read via closure]
    Object:  1 [read after assignment]
    

    将此与另一个示例进行对比,在该示例中,除了将 @Published 替换为 CurrentValueSubject 之外,我们保持相同:

    class CurrentValueSubjectModel {
        var number: CurrentValueSubject<Int, Never> = .init(0)
    }
    
    let cvsModel = CurrentValueSubjectModel()
    
    cvsModel.number.sink { number in
        print("Closure: \(number)")
        print("Object:  \(cvsModel.number.value) [read via closure]")
    }
    
    cvsModel.number.send(1)
    
    print("Object:  \(cvsModel.number.value) [read after assignment]")
    

    输出:

    Closure: 0
    Object:  0 [read via closure]
    Closure: 1
    Object:  1 [read via closure] // <— Here is the difference
    Object:  1 [read after assignment]
    

    number 更新为1 后,读取对象的CurrentValueSubject 的值属性 闭包打印新值而不是旧值,就像@Published 一样强>。

    总之,在您的ObservableObjects 中使用@Published 来获取您的SwiftUI 视图。如果您希望创建某种模型对象,其实例属性包含当前值并且也在设置后发布它的更改,请使用CurrentValueSubject

    【讨论】:

      【解决方案4】:

      @Published 的一个优点是它可以充当私有可变、公共不可变的 CurrrentValueSubject。

      比较:

      @Published private(set) var text = "someText"
      

      与:

      let text = CurrentValueSubject<String, Never>("someText")
      

      在设计 API 时,您通常希望允许客户端读取当前值并订阅更新,但阻止它们直接设置值。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-12-25
        • 2020-05-10
        • 2014-09-20
        • 2010-10-28
        • 2015-10-04
        • 2012-08-12
        • 2011-02-18
        • 2019-12-21
        相关资源
        最近更新 更多