CurrentValueSubject 和@Published 之间的区别
Difference between CurrentValueSubject and @Published
所以我正在研究 combine 并提出了这个问题。
使用 CurrentValueSubject
(并使用 currentValueSubject.value
设置其值)或使用 @Published var
并使用 $
访问其发布者之间有什么真正的区别吗?我的意思是我知道 returns 和 Subject
而不是 Publisher
,但我能找到的唯一真正区别是 CurrentValueSubject
更有用,因为你可以声明它协议。
我真的不明白 @Published
如果我们只使用 PassthroughSubject
会有什么用,我在这里遗漏了什么吗?
请注意,这是使用 UIKit,它可能有 SwiftUI 的其他用途。
谢谢。
@Published 只是一种更简洁地使用 CurrentValueSubject 的快速方法。当我调试我的一个应用程序并查看 $paramName 返回的类型时,它实际上只是一个 CurrentValueSubject:
po self.$books
▿ Publisher
▿ subject : <CurrentValueSubject<Array<Book>, Never>: 0x6000034b8910>
我想使用 CurrentValueSubject 而不是 @Published 的好处之一可能是允许您使用错误类型?
注意:尽管现在是一个 CurrentValueSubject,但我永远不会依赖那个假设。
CurrentValueSubject
是一个值,一个发布者和一个订阅者。
遗憾的是,当在 ObservableObject 中使用时,它不会触发 objectWillChange.send()
。
您可以指定错误类型。
@Published
是一个 属性 包装器,因此:
- 顶级代码尚不支持。
- 协议声明不支持它。
- 只能在class内使用。
@Published
在 ObservableObject 内部使用时自动触发 objectWillChange.send()
。
如果您尝试从后台队列发布到 @Published
包装 属性,Xcode 将发出警告。可能是因为 objectWillChange.send()
必须从主线程调用。
其发布者的错误类型是Never
我最反对 @Published
的是它不能充当订阅者,并且与当前值主题相比,设置 Combine 管道需要额外的管道。
我们可以在协议中声明一个@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
的一个优点是它可以充当 private-mutable、public-immutable CurrrentValueSubject。
比较:
@Published private(set) var text = "someText"
与:
let text = CurrentValueSubject<String, Never>("someText")
在设计 API 时,您通常希望允许客户端读取当前值并订阅更新,但阻止它们直接设置值。
我发现自己又回到了这个 post,所以我想对 @Published
和 CurrentValueSubject
之间的区别添加一些额外的见解。
可以在 @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.
此外,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
.
使用@Published 时有一项限制。
您只能在 Class 的属性上使用 @Published,而 CurrentValueSubject 也可以用于结构
所以我正在研究 combine 并提出了这个问题。
使用 CurrentValueSubject
(并使用 currentValueSubject.value
设置其值)或使用 @Published var
并使用 $
访问其发布者之间有什么真正的区别吗?我的意思是我知道 returns 和 Subject
而不是 Publisher
,但我能找到的唯一真正区别是 CurrentValueSubject
更有用,因为你可以声明它协议。
我真的不明白 @Published
如果我们只使用 PassthroughSubject
会有什么用,我在这里遗漏了什么吗?
请注意,这是使用 UIKit,它可能有 SwiftUI 的其他用途。
谢谢。
@Published 只是一种更简洁地使用 CurrentValueSubject 的快速方法。当我调试我的一个应用程序并查看 $paramName 返回的类型时,它实际上只是一个 CurrentValueSubject:
po self.$books
▿ Publisher
▿ subject : <CurrentValueSubject<Array<Book>, Never>: 0x6000034b8910>
我想使用 CurrentValueSubject 而不是 @Published 的好处之一可能是允许您使用错误类型?
注意:尽管现在是一个 CurrentValueSubject,但我永远不会依赖那个假设。
CurrentValueSubject
是一个值,一个发布者和一个订阅者。
遗憾的是,当在 ObservableObject 中使用时,它不会触发 objectWillChange.send()
。
您可以指定错误类型。
@Published
是一个 属性 包装器,因此:
- 顶级代码尚不支持。
- 协议声明不支持它。
- 只能在class内使用。
@Published
在 ObservableObject 内部使用时自动触发 objectWillChange.send()
。
@Published
包装 属性,Xcode 将发出警告。可能是因为 objectWillChange.send()
必须从主线程调用。
其发布者的错误类型是Never
我最反对 @Published
的是它不能充当订阅者,并且与当前值主题相比,设置 Combine 管道需要额外的管道。
我们可以在协议中声明一个@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
的一个优点是它可以充当 private-mutable、public-immutable CurrrentValueSubject。
比较:
@Published private(set) var text = "someText"
与:
let text = CurrentValueSubject<String, Never>("someText")
在设计 API 时,您通常希望允许客户端读取当前值并订阅更新,但阻止它们直接设置值。
我发现自己又回到了这个 post,所以我想对 @Published
和 CurrentValueSubject
之间的区别添加一些额外的见解。
可以在 @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.
此外,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
.
使用@Published 时有一项限制。
您只能在 Class 的属性上使用 @Published,而 CurrentValueSubject 也可以用于结构