[英]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
是一个属性包装器,因此:
@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
.我发现自己回到了这篇文章,所以觉得我会在@Published
和CurrentValueSubject
之间的区别上添加一些额外的见解。
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.