简体   繁体   English

CurrentValueSubject 和 @Published 之间的区别

[英]Difference between CurrentValueSubject and @Published

So I'm digging into combine and this question came up.所以我正在研究 combine 并提出了这个问题。

Is there any real difference between using CurrentValueSubject (and setting its value using currentValueSubject.value ) or using a @Published var and accessing its publisher with a $ ?使用CurrentValueSubject (并使用currentValueSubject.value设置其值)或使用@Published var并使用$访问其发布者之间有什么真正的区别吗? I mean I know one returns a Subject instead of a Publisher , but the only real difference I could find is that CurrentValueSubject is way more useful because you can declare it on a protocol.我的意思是我知道返回的是Subject而不是Publisher ,但我能找到的唯一真正区别是CurrentValueSubject更有用,因为您可以在协议上声明它。

I really don't understand how @Published can be useful if we can just use PassthroughSubject , am I missing something here?我真的不明白@Published如果我们可以使用PassthroughSubject会有什么用,我在这里遗漏了什么吗? Mind you, this is using UIKit , it may have other uses for SwiftUI.请注意,这是使用 UIKit ,它可能对 SwiftUI 有其他用途。

Thank you.谢谢你。

@Published is just a quick way to use CurrentValueSubject a little neater. @Published 只是一种更简洁地使用 CurrentValueSubject 的快速方法。 When I debug one of my apps and look at the type returned by $paramName, it's actually just a CurrentValueSubject:当我调试我的一个应用程序并查看 $paramName 返回的类型时,它实际上只是一个 CurrentValueSubject:

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

I guess one benefit of using CurrentValueSubject instead of @Published may be to allow you to use the error type?我想使用 CurrentValueSubject 而不是 @Published 的一个好处可能是允许您使用错误类型?

Note: Despite being a CurrentValueSubject right now I'd never rely on that assumption.注意:尽管我现在是 CurrentValueSubject,但我永远不会依赖这个假设。

CurrentValueSubject is a value, a publisher and a subscriber all in one. CurrentValueSubject是一个值,一个发布者和一个订阅者合而为一。

Sadly it doesn't fire objectWillChange.send() when used inside an ObservableObject.遗憾的是,在 ObservableObject 中使用时它不会触发objectWillChange.send()

You can specify an error type.您可以指定错误类型。

@Published is a property wrapper, thus: @Published是一个属性包装器,因此:

  • It is not yet supported in top-level code.顶级代码尚不支持它。
  • It is not supported in a protocol declaration.协议声明中不支持它。
  • It can only be used within a class.它只能在 class 中使用。

@Published automatically fires objectWillChange.send() when used inside an ObservableObject. @Published在 ObservableObject 中使用时会自动触发objectWillChange.send()

Xcode will emit a warning if your try to publish to @Published wrapped property from a background queue.如果您尝试从后台队列发布到@Published包装属性,Xcode 将发出警告。 Probably because objectWillChange.send() must be called from the main thread.可能是因为objectWillChange.send()必须从主线程调用。

The error type of its publisher is Never其发布者的错误类型是Never

My biggest beef against @Published is that it can't behave as a subscriber and setting up Combine pipelines requires additional plumbing compared to a Current Value Subject.我对@Published最大的不满是它不能充当订阅者,并且与当前值主题相比,设置组合管道需要额外的管道。

We can declare a @Published property inside a protocol.我们可以在协议中声明@Published属性。 Not very pretty...不是很漂亮...

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 }
}

I found myself coming back to this post so felt I'd add some extra insight in to the difference between @Published and CurrentValueSubject .我发现自己回到了这篇文章,所以觉得我会在@PublishedCurrentValueSubject之间的区别上添加一些额外的见解。

One main difference can be found in the documentation for @Published :@Published的文档中可以找到一个主要区别:

When the property changes, publishing occurs in the property's willSet block, meaning subscribers receive the new value before it's actually set on the property.当属性发生变化时,会在属性的 willSet 块中进行发布,这意味着订阅者会在新值实际设置在属性上之前接收到新值。

Additionally, conversation on the Swift Forums note that @Published is intended for use with SwiftUI.此外, Swift 论坛上的对话指出, @Published旨在与 SwiftUI 一起使用。

With regards to @Published publishing in the willSet block of it's property, consider the following example:关于@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]")

This produces the following output:这将产生以下 output:

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

Contrast this with another example where we keep everything the same, except replacing @Published with CurrentValueSubject :将此与另一个示例进行对比,在该示例中,除了将@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]")

Output: Output:

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

After updating number to 1, reading the object's CurrentValueSubject 's value property within the closure prints the new value instead of the old value as with @Published .number更新为 1 后,闭包中读取对象的CurrentValueSubject的 value 属性将打印新值而不是与@Published一样的旧值

In summary, use @Published within your ObservableObjects for your SwiftUI views.总之,在您的ObservableObjects中为您的 SwiftUI 视图使用@Published If you're looking to create some sort of model object with an instance property that holds a current value and also publishes it's changes after they are set, use CurrentValueSubject .如果您要创建某种类型的 model object ,其实例属性包含当前值在设置后发布它的更改,请使用CurrentValueSubject

One advantage on @Published is that it can act as a private-mutable, public-immutable CurrrentValueSubject. @Published的一个优点是它可以充当私有可变、公共不可变的 CurrrentValueSubject。

Compare:相比:

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

with:和:

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

When designing APIs you often want to allow clients to read the current value and subscribe to updates but prevent them from setting values directly.在设计 API 时,您通常希望允许客户端读取当前值并订阅更新,但阻止它们直接设置值。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM