在遇到一些合并问题时,我遇到了https://developer.apple.com/documentation/combine/publisher中的“使用多个订户”部分:
func multicast<S>(() -> S) -> Publishers.Multicast<Self, S>
func multicast<S>(subject: S) -> Publishers.Multicast<Self, S>
但是,当我尝试确认我的假设,即发送给多个订户时将需要多播时,我发现尝试使用该游乐场代码(从https://github.com/AvdLee/CombineSwiftPlayground/blob/master/Combine.playground/Pages/Combining%20Publishers.xcplaygroundpage/Contents.swift修改)时并不必要(运行于10.14)。 Xcode 11.0 beta 3(11M362v)中的5):
enum FormError: Error { }
let usernamePublisher = PassthroughSubject<String, FormError>()
let passwordPublisher = PassthroughSubject<String, FormError>()
let validatedCredentials = Publishers.CombineLatest(usernamePublisher, passwordPublisher)
.map { (username, password) -> (String, String) in
return (username, password)
}
.map { (username, password) -> Bool in
!username.isEmpty && !password.isEmpty && password.count > 12
}
.eraseToAnyPublisher()
let firstSubscriber = validatedCredentials.sink { (valid) in
print("First Subscriber: CombineLatest: Are the credentials valid: \(valid)")
}
let secondSubscriber = validatedCredentials.sink { (valid) in
print("Second Subscriber: CombineLatest: Are the credentials valid: \(valid)")
}
// Nothing will be printed yet as `CombineLatest` requires both publishers to have send at least one value.
usernamePublisher.send("avanderlee")
passwordPublisher.send("weakpass")
passwordPublisher.send("verystrongpassword")
此打印:
First Subscriber: CombineLatest: Are the credentials valid: false
Second Subscriber: CombineLatest: Are the credentials valid: false
First Subscriber: CombineLatest: Are the credentials valid: true
Second Subscriber: CombineLatest: Are the credentials valid: true
因此,似乎不需要多播即可寻址多个订户。还是我错了?
那么,这些多播功能有什么作用,我将如何使用它们?一些示例代码会很好。
谢谢
Lars
答案 0 :(得分:2)
PassthroughSubject并不是一个很好的示例,因为它是一个类,可以为您提供参考语义。因此,在一个简单的情况下,只要主题发出一个,两个订阅者就可以直接订阅它并同时接收相同的值。
但这是一个更好的测试用例(受Cocoa With Love的讨论启发):
let pub1 = Timer.publish(every: 1, on: .main, in: .default).autoconnect()
let sub = CurrentValueSubject<Int,Never>(0)
let scan = sub.scan(10) {i,j in i+j}
pub1.sink { _ in let i = sub.value; sub.value = i+1 }.store(in:&storage)
scan.sink { print("a", $0) }.store(in:&storage)
delay(3) {
scan.sink { print("b", $0) }.store(in:&self.storage)
}
当第二个sink
作为该管道的新订阅者出现时,得出的结果肯定很奇怪:
a 10
a 11
a 13
a 16
b 13
a 20
b 17
a 25
b 22
a 31
b 28
a 38
b 35
接收器a
和b
的编号序列彼此不同,这实际上是因为scan
是一个结构。如果我们希望他们获得相同的数字,则可以使用多播:
let scan = sub.scan(10) {i,j in i+j}.multicast {PassthroughSubject()}.autoconnect()
产生
a 10
a 11
a 13
a 16
a 20
b 20
a 25
b 25
这是连贯的。
但是, still 并不能证明您需要multicast
,因为您可以通过说.share()
来完成同一件事。我不清楚multicast
和share
之间的区别。
答案 1 :(得分:0)
An answer/reference from the swift forums意味着多播方法旨在基于.share()运算符。来自Philippe's post:
在这种情况下,它用于将上游连接到PassthroughSubject,然后自动连接。通常,当订阅者收到订阅时,它将取消第一个订阅之后的所有其他订阅,多播会对此行为进行转义操作并处理多个订阅。
在实践中,如果您想通过组合中的多个管道拆分流和多播事件更新,则似乎最实用的方法是创建一个@Published属性,让任何上游管道使用.assign()或在内部进行更新.sink(),然后通过@Published属性与订阅者建立其他管道。