简体   繁体   English

Swift 组合:一个接一个地运行发布者列表,并发布第一个非零元素

[英]Swift Combine: Run a list of publishers one after the other, and publish the first non-nil element

I have a list of combine publishers that each publish one optional value.我有一个联合发布者列表,每个发布者发布一个可选值。 From this list, i want to create a publisher, that runs the upstream publishers in the sequence they appear in the list, one after the other , and then publish the first non-nil item i can find.从这个列表中,我想创建一个发布者,它按照它们在列表中出现的顺序运行上游发布者,一个接一个,然后发布我能找到的第一个非零项目。

My first approach was我的第一种方法是

publishers
    .publisher
    .flatMap(identity)
    .first(where: {$0 != nil})

but this causes all publishers to run, and the fastest to win.但这会导致所有发布者都运行,并且以最快的速度获胜。

I created a minimal example with a solution that comes close to what i want to achieve.我创建了一个最小的示例,其解决方案接近我想要实现的目标。

import Combine
import Foundation
import PlaygroundSupport
PlaygroundPage.current.needsIndefiniteExecution = true

func delayedPublisher<Value>(_ value: Value?, delay after: Double) -> AnyPublisher<Value?, Never> {
    let p = PassthroughSubject<Value?, Never>()
    DispatchQueue.main.asyncAfter(deadline: .now() + after) {
        p.send(value)
        p.send(completion: .finished)
    }
    return p.eraseToAnyPublisher()
}

let delays = [1,2,3,4,5].map({ Bool.random() ? nil : $0 }).shuffled()
print("Creating publishers with values and delays (in seconds)", delays)
let myPublishers = delays
    .map{ delayedPublisher($0, delay: Double($0 ?? 1))
        .print("\(String(describing: $0))")
        .eraseToAnyPublisher() }

let cancel = myPublishers
    .publisher
    .flatMap { $0 }
    .collect()
    .map { resultList in
        resultList.first(where: { $0 != nil }) ?? nil
    }
    .sink { result in
        print("result:", result ?? "nil")
    }

This creates a bunch of publishers with different delays, that may or may not produce a value.这会创建一堆具有不同延迟的发布者,这些发布者可能会也可能不会产生价值。 I then collect all results, and pick the first non-nil value.然后我收集所有结果,并选择第一个非零值。 The problem is问题是

  • All effects are run.运行所有效果。 I just want to run effects until i ran one that produces a value.我只想运行效果,直到我运行一个产生价值的效果。
  • The results arrive in the order the publishers complete.结果按照发布者完成的顺序到达。 I need to restore the original order after, which is possible but awkward in my specific example.之后我需要恢复原始顺序,这在我的具体示例中是可能的但很尴尬。

I did my research but found nothing like that, perhaps because combine is not really designed to do that sort of thing.我做了我的研究,但没有发现类似的东西,也许是因为 combine 并不是真正设计用来做那种事情的。 So any pointers are appreciated.因此,任何指针都值得赞赏。

The approach is almost like your original one, but you need to restrict flatMap to run at most one publisher at a time with maxPublishers parameter:该方法几乎就像您原来的方法一样,但是您需要使用maxPublishers参数限制flatMap一次最多运行一个发布者:

publishers
    .publisher
    .flatMap(maxPublishers: .max(1), { $0 })
    .compactMap { $0 } // Remove all nil values and unwrap the non-nil ones.
    .first()

Here's a simple extension to Publisher这是 Publisher 的一个简单扩展

extension Publisher {
  func chain(with publisher: @escaping () -> AnyPublisher<Output, Failure>) -> AnyPublisher<Output, Failure> {
    self.flatMap { _ in publisher() }.eraseToAnyPublisher()
  } 
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 快速范围规则-设置非零值后为零 - Swift Scoping Rules — nil value after setting a non-nil value Swift 合并 - 合并发布者而不等待所有发布者发出第一个元素 - Swift Combine - combining publishers without waiting for all publishers to emit first element 将非nil对象设置为弱属性会第二次返回nil,但第一次不会返回nil - Setting a non-nil object to a weak property returns nil second time but not first one 非零分配后,实例属性仍然为零 - Instance property remains nil after non-nil assignment &#39;UICollectionView必须使用非nil布局参数初始化&#39;-Swift 4 - 'UICollectionView must be initialized with a non-nil layout parameter' - Swift 4 UiCollectionView必须使用非nil布局参数初始化Swift 3 - UiCollectionView must be initialized with a non-nil layout parameter Swift 3 ViewController的出口视图首先是非零,然后从bundle加载时为nil - ViewController's outlet view first non-nil, then nil when loading from bundle 使用非零值设置后,UIImageView.image为nil - UIImageView.image is nil after being set with non-nil value 使用同步 DispatchQueue 设置非零值的最“类似 Swift”/干净的方法是什么? - What's the most "Swift-like"/clean way to set a non-nil value with a sync DispatchQueue? Swift:即使文件不存在,downloadTaskWithURL 有时也会以非零位置“成功” - Swift: downloadTaskWithURL sometimes "succeeds" with non-nil location even though file does not exist
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM