我有一组发布者,我想等待它们,直到所有发布者都发出一个值,然后处理结果.

我try 使用collect()Publishers.MergeMany(编辑:使用MergeMany,因为我正在寻找一个可以扩展到40个或更多出版商的解决方案),但Collect只按收到结果的顺序收集结果,而不尊重值的顺序,从而正确地关联出版商和价值.

为了简化代码并说明问题,以下是Playround代码:

import Combine

var cancellables = [AnyCancellable]()

let stringPublishers = [
    Just("1").delay(for: RunLoop.SchedulerTimeType.Stride(Double.random(in: 0.1...1.0)), scheduler: RunLoop.main),
    Just("2").delay(for: RunLoop.SchedulerTimeType.Stride(Double.random(in: 0.1...1.0)), scheduler: RunLoop.main),
    Just("3").delay(for: RunLoop.SchedulerTimeType.Stride(Double.random(in: 0.1...1.0)), scheduler: RunLoop.main),
    Just("4").delay(for: RunLoop.SchedulerTimeType.Stride(Double.random(in: 0.1...1.0)), scheduler: RunLoop.main),
    Just("5").delay(for: RunLoop.SchedulerTimeType.Stride(Double.random(in: 0.1...1.0)), scheduler: RunLoop.main)
]

Publishers.MergeMany(stringPublishers).collect().sink { value in
    print(value)
}.store(in: &cancellables)

运行代码,结果通常是无序的,比如["2", "4", "5", "3", "1"]["1", "4", "5", "3", "2"]等等. 我怎么才能总是得到["1", "2", "3", "4", "5"]分呢?

我try 在这里修改solution,但遇到了问题,因为我的inputArray已经是一个由Publishers组成的数组,而不是整数值或字符串的普通值.

推荐答案

下面是一个函数,它将接受任意数量的发布者,并将它们组合成包含遵守顺序的元素数组的单个发布者:

func combineLatest<Pub>(_ pubs: [Pub]) -> AnyPublisher<[Pub.Output], Pub.Failure> where Pub: Publisher {
    guard !pubs.isEmpty else { return Empty().eraseToAnyPublisher() }
    return pubs.dropFirst().reduce(pubs[0].map { [$0] }.eraseToAnyPublisher()) { partial, next in
        partial.combineLatest(next)
            .map { $0 + [$1] }
            .eraseToAnyPublisher()
    }
}

它的使用方法如下:

combineLatest(stringPublishers).sink(receiveValue: {
    print($0)
})
.store(in: &cancellables)

如果你不喜欢免费的功能,可以把它放在一个扩展中:

extension Collection where Element: Publisher {
    func combineLatest() -> AnyPublisher<[Element.Output], Element.Failure> {
        guard !isEmpty else { return Empty().eraseToAnyPublisher() }
        return dropFirst().reduce(first!.map { [$0] }.eraseToAnyPublisher()) { partial, next in
            partial.combineLatest(next)
                .map { $0 + [$1] }
                .eraseToAnyPublisher()
        }
    }
}

Swift相关问答推荐

可编码:将字符串解码为自定义类型(ISO 8601日期,无时间组件)

为什么在Swift属性Wrapper中需要类型注释?

如何禁用MacOS上SwiftUI中按钮周围的聚焦环(或高亮显示)?

是否在核心数据中使用Uint?

一种函数,用于判断变量的类型是否为在SWIFT中作为参数传递的类型

为什么 Swift URL 的 init?(string: String,relativeTo: URL?) 仅添加协议?

SwiftUI 无法在实时活动中显示 SpriteView

如何从 RC 加载场景作为 ModelEntity 而不是普通实体?

是否有一个带有空初始值设定项的 Swift 类/ struct 的标准协议

TextField 键入未完成

状态变量更改后,SwiftUI 视图不会更改

Swift 全局函数列表

P384 公钥获取IncorrectParameterSize

如何在 SwiftUI 中正确实现Collection 夹?

Vapor, fluent 使用 PostgreSQL 保存/创建复杂模型

UnkeyedEncodingContainer 和 KeyedEncodingContainerProtocol 中的 superEncoder 是什么?

如何快速制作虚线?

Swift - 导入我的 swift 类

NSLocationWhenInUseUsageDescription 警告,但我已经添加了

iPhone 纵向和 iPad 横向的通用应用程序