SqA*_*org 4 swift ios13 combine macos-catalina
在努力解决一些联合收割机问题时,我遇到了https://developer.apple.com/documentation/combine/publisher中的“使用多个订阅者”部分:
func multicast<S>(() -> S) -> Publishers.Multicast<Self, S>
func multicast<S>(subject: S) -> Publishers.Multicast<Self, S>
Run Code Online (Sandbox Code Playgroud)
然而,当我试图确认我的假设时,在发送给多个订阅者时需要多播,我发现在尝试这个游乐场代码时这是不必要的(修改自https://github.com/AvdLee/CombineSwiftPlayground/blob/ ) master/Combine.playground/Pages/Combining%20Publishers.xcplaygroundpage/Contents.swift)(在 Xcode 版本 11.0 beta 3 (11M362v) 中的 10.14.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")
Run Code Online (Sandbox Code Playgroud)
这打印:
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
Run Code Online (Sandbox Code Playgroud)
因此,似乎不需要多播来寻址多个订阅者。还是我错了?
那么,这些多播功能的用途是什么以及如何使用它们?一些示例代码会很好。
谢谢,
拉尔斯
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)
}
Run Code Online (Sandbox Code Playgroud)
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
Run Code Online (Sandbox Code Playgroud)
接收器a并b获得彼此不同的一系列数字,实际上是因为它scan是一个结构。如果我们希望它们获得相同的号码,我们可以使用多播:
let scan = sub.scan(10) {i,j in i+j}.multicast {PassthroughSubject()}.autoconnect()
Run Code Online (Sandbox Code Playgroud)
这产生
a 10
a 11
a 13
a 16
a 20
b 20
a 25
b 25
Run Code Online (Sandbox Code Playgroud)
这是连贯的。
然而,这仍然不能证明你需要multicast,因为你可以通过说来完成同样的事情.share()。我不清楚 和 之间有什么multicast区别share。
| 归档时间: |
|
| 查看次数: |
3343 次 |
| 最近记录: |