CurrentValueSubject 和 @Published 之间的区别

Myk*_*kod 16 uikit ios swift combine

所以我正在研究结合,这个问题就出现了。

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

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

谢谢你。

Myc*_*ner 14

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

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

您可以指定错误类型。

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

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

@PublishedobjectWillChange.send()在 ObservableObject 中使用时自动触发。

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

其发布者的错误类型是 Never

我最大的反对@Published是它不能作为订阅者运行,并且与当前值主题相比,设置组合管道需要额外的管道。

我们可以@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 }
}
Run Code Online (Sandbox Code Playgroud)


Jas*_*son 13

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

po self.$books
? Publisher
  ? subject : <CurrentValueSubject<Array<Book>, Never>: 0x6000034b8910>
Run Code Online (Sandbox Code Playgroud)

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

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

  • 谢谢!另一个好处是能够在协议上声明它:) (3认同)

Mih*_*ian 9

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

比较:

@Published private(set) var text = "someText"
Run Code Online (Sandbox Code Playgroud)

和:

let text = CurrentValueSubject<String, Never>("someText")
Run Code Online (Sandbox Code Playgroud)

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


Nei*_*ith 5

我发现自己又回到了这篇文章,所以觉得我会对@Published和之间的区别添加一些额外的见解CurrentValueSubject

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

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

此外,Swift 论坛上的对话说明@Published旨在与 SwiftUI 一起使用。

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

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]")
Run Code Online (Sandbox Code Playgroud)

这会产生以下输出:

Closure: 0
Object:  0 [read via closure]
Closure: 1
Object:  0 [read via closure]
Object:  1 [read after assignment]
Run Code Online (Sandbox Code Playgroud)

将此与另一个我们保持所有内容相同的示例进行对比,除了替换@PublishedCurrentValueSubject

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]")
Run Code Online (Sandbox Code Playgroud)

输出:

Closure: 0
Object:  0 [read via closure]
Closure: 1
Object:  1 [read via closure] // <— Here is the difference
Object:  1 [read after assignment]
Run Code Online (Sandbox Code Playgroud)

更新后number至1,阅读对象CurrentValueSubject的价值属性关闭打印新值代替旧值与@Published

总之,@Published在您ObservableObjects的 SwiftUI 视图中使用。如果您希望创建某种模型对象,其实例属性保存当前值在设置后发布更改,请使用CurrentValueSubject.