Swift Combine:如何收集结果时保留发布者的输出顺序?
解决Combine中MergeMany收集结果保留原始顺序的问题
核心思路
Publishers.MergeMany是按发布者完成顺序输出值,而我们需要对应原始数组的位置顺序。解决关键是给每个发布者的结果绑定它在原数组中的索引,收集后按索引排序再提取值。
实现代码
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) ] // 给每个发布者绑定索引,将结果包装成(索引, 值)的元组 let indexedPublishers = stringPublishers.enumerated().map { index, publisher in publisher.map { (index, $0) } } // 合并带索引的发布者,收集后按索引排序并提取最终值 Publishers.MergeMany(indexedPublishers) .collect() .map { tuples in tuples.sorted(by: { $0.0 < $1.0 }).map { $0.1 } } .sink { value in print(value) // 始终输出 ["1", "2", "3", "4", "5"] } .store(in: &cancellables)
代码说明
- 绑定索引:用
enumerated()遍历原发布者数组,给每个发布者的结果添加它在原数组中的位置索引,让每个值都能追溯到原始位置。 - 排序提取:收集所有带索引的元组后,先按索引从小到大排序,再提取元组中的值,就能得到和原发布者数组顺序完全一致的结果。
- 兼容性:该方案完全支持40个及以上的发布者,
MergeMany和后续排序操作不会因数量过多出现异常(只要内存能容纳所有结果)。
内容的提问来源于stack exchange,提问作者Rodolfo Romero
相关产品推荐
相关产品推荐

