Swift Combine – 等待所有发布者

huangapple go评论70阅读模式
英文:

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来合并三个发布者的属性(acceptedTermsacceptedPrivacyname),并在它们都接收到值后,更新submitButtonisEnabled属性以确定是否可以提交。

英文:

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.

Swift Combine – 等待所有发布者

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 = &quot;&quot;

    // Keep a reference to the subscription so it&#39;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 ?? &quot;&quot;
    }

    private var validToSubmit: AnyPublisher&lt;Bool, Never&gt; {
        return Publishers.CombineLatest3($acceptedTerms, $acceptedPrivacy, $name)
            .map { terms, pricacy, name in
                terms &amp;&amp; pricacy &amp;&amp; !name.isEmpty
            }.eraseToAnyPublisher()
    }

huangapple
  • 本文由 发表于 2020年1月6日 23:50:12
  • 转载请务必保留本文链接:https://go.coder-hub.com/59615078.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定