英文:
Swift Combine - Wait for all publishers
问题
I am trying to use Swift combine to run many tasks with the same result.
at the moment each task is a publisher that will emit a result. now I am facing a problem that I have to wait for all publishers to emit the element then moving on. kind of like dispatch group. I found zip(with:::_) operator which takes 4 publishers.
> https://developer.apple.com/documentation/combine/passthroughsubject/3333571-zip
but what if you have an array of publishers (in case that they emit the same kind of element) ? is there any way to do that?
我正在尝试使用Swift Combine来运行许多具有相同结果的任务。目前,每个任务都是一个发布者,会发出一个结果。现在我面临的问题是我必须等待所有发布者发出元素然后继续进行。有点像dispatch group。我找到了zip(with:::_)操作符,它接受4个发布者。
但是如果你有一个发布者数组(在它们发出相同类型的元素的情况下)呢?有没有办法做到这一点?
英文:
I am trying to use Swift combine to run many tasks with the same result.
at the moment each task is a publisher that will emit a result. now I am facing a problem that I have to wait for all publishers to emit the element then moving on. kind of like dispatch group. I found zip(with:::_) operator which takes 4 publishers.
> https://developer.apple.com/documentation/combine/passthroughsubject/3333571-zip
but what if you have an array of publishers (in case that they emit the same kind of element) ? is there any way to do that?
答案1
得分: 31
你可以使用 MergeMany
来创建一个单一的下游接收来自多个上游的所有发射值,然后在合并的发布者上调用 collect()
来一次性发射所有值。
let pubs = [Just(1), Just(2), Just(3)]
let downstream = Publishers.MergeMany(pubs).collect()
英文:
You can use MergeMany
to create a single downstream receiving all emitted values from several upstreams and then call collect()
on the merged publisher to emit all values at once.
let pubs = [Just(1),Just(2),Just(3)]
let downstream = Publishers.MergeMany(pubs).collect()
答案2
得分: 0
CombineLatest是一个用于合并多个发布者属性并在它们都接收到值后执行的方法。根据WWDC中的示例,你可以如下使用它:
class ViewController: UIViewController {
@IBOutlet private var termsSwitch: UISwitch!
@IBOutlet private var privacySwitch: UISwitch!
@IBOutlet private var nameField: UITextField!
@IBOutlet private var submitButton: UIButton!
@Published private var acceptedTerms: Bool = false
@Published private var acceptedPrivacy: Bool = false
@Published private var name: String = ""
// 保持对订阅的引用,以便在我们被销毁时取消订阅。
private var termsStream: AnyCancellable?
override func viewDidLoad() {
super.viewDidLoad()
// 在视图加载后进行任何额外的设置。
termsStream = validToSubmit
.receive(on: RunLoop.main)
.assign(to: \.isEnabled, on: submitButton)
}
@IBAction private func acceptTerms(_ sender: UISwitch) {
acceptedTerms = sender.isOn
}
@IBAction private func acceptPrivacy(_ sender: UISwitch) {
acceptedPrivacy = sender.isOn
}
@IBAction private func nameChanged(_ sender: UITextField) {
name = sender.text ?? ""
}
private var validToSubmit: AnyPublisher<Bool, Never> {
return Publishers.CombineLatest3($acceptedTerms, $acceptedPrivacy, $name)
.map { terms, privacy, name in
terms && privacy && !name.isEmpty
}.eraseToAnyPublisher()
}
}
这段代码演示了如何使用CombineLatest来合并三个发布者的属性(acceptedTerms
,acceptedPrivacy
和name
),并在它们都接收到值后,更新submitButton
的isEnabled
属性以确定是否可以提交。
英文:
Well you can use CombineLatest. You can input upto 3 publisher properties and have a single downstream which will be executed once all publishers are received.
As per the example given in WWDC you can use it as follows.
class ViewController: UIViewController {
@IBOutlet private var termsSwitch: UISwitch!
@IBOutlet private var privacySwitch: UISwitch!
@IBOutlet private var nameField: UITextField!
@IBOutlet private var submitButton: UIButton!
@Published private var acceptedTerms: Bool = false
@Published private var acceptedPrivacy: Bool = false
@Published private var name: String = ""
// Keep a reference to the subscription so it's
// only cancelled when we are deallocated.
private var termsStream: AnyCancellable?
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
termsStream = validToSubmit
.receive(on: RunLoop.main)
.assign(to: \.isEnabled, on: submitButton)
}
@IBAction private func acceptTerms(_ sender: UISwitch) {
acceptedTerms = sender.isOn
}
@IBAction private func acceptPrivacy(_ sender: UISwitch) {
acceptedPrivacy = sender.isOn
}
@IBAction private func nameChanged(_ sender: UITextField) {
name = sender.text ?? ""
}
private var validToSubmit: AnyPublisher<Bool, Never> {
return Publishers.CombineLatest3($acceptedTerms, $acceptedPrivacy, $name)
.map { terms, pricacy, name in
terms && pricacy && !name.isEmpty
}.eraseToAnyPublisher()
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论