Swift Combine:如何按顺序合并多个嵌套Publisher的输出结果
Combine 顺序执行多个Publisher的实现方案
错误点说明
现有代码存在两个核心问题:
- 直接对Swift原生数组
objArray调用flatMap是数组的原生遍历方法,不是Combine框架的操作符,无法实现Publisher的拼接逻辑 sink方法返回的是AnyCancellable类型的订阅对象,不是输出值的数组,不能直接赋值给[String]类型的results变量
正确实现方案
方案1:兼容低版本系统的reduce拼接方案(iOS13+/macOS10.15+可用)
通过reduce配合append操作符逐个拼接Publisher,保证前一个Publisher完成后才订阅下一个:
import Combine protocol StringPublisher { var stringValues: AnyPublisher<String, Error> { get } } // 示例协议实现,用于测试 struct StringPublisher1: StringPublisher { var stringValues: AnyPublisher<String, Error> init(_ values: String...) { stringValues = values.publisher .setFailureType(to: Error.self) .eraseToAnyPublisher() } } struct StringPublisher2: StringPublisher { var stringValues: AnyPublisher<String, Error> init(_ values: String...) { stringValues = values.publisher .setFailureType(to: Error.self) .eraseToAnyPublisher() } } let objArray:[StringPublisher] = [StringPublisher1("a","b","c"), StringPublisher2("x","y","z")] var cancellables = Set<AnyCancellable>() // 取出所有待执行的Publisher let allPublishers = objArray.map(\.stringValues) // 拼接生成顺序执行的Publisher let sequentialPublisher = allPublishers.dropFirst() .reduce(into: allPublishers.first!) { result, nextPublisher in result = result.append(nextPublisher).eraseToAnyPublisher() }
如果需要收集所有输出到数组:
var results: [String] = [] sequentialPublisher .collect() // 等待所有Publisher执行完成,合并所有输出为单个数组 .sink( receiveCompletion: { completion in if case .failure(let error) = completion { print("执行出错:\(error)") } }, receiveValue: { allValues in results = allValues print(results) // 输出:["a", "b", "c", "x", "y", "z"] } ) .store(in: &cancellables)
如果需要边输出边处理,去掉collect即可:
sequentialPublisher .sink( receiveCompletion: { _ in }, receiveValue: { value in print(value) // 按顺序输出:a、b、c、x、y、z } ) .store(in: &cancellables)
方案2:高版本系统简便写法(iOS14+/macOS11+可用)
通过Publishers.Sequence将数组转为Combine序列,配合flatMap的maxPublishers参数限制同时订阅数量为1,实现顺序执行:
Publishers.Sequence(sequence: objArray) .flatMap(maxPublishers: .max(1)) { $0.stringValues } .sink( receiveCompletion: { _ in }, receiveValue: { value in print(value) // 按顺序输出 } ) .store(in: &cancellables)
注意事项
- 所有内部Publisher的失败类型必须保持一致,任意一个Publisher抛出错误,整个执行序列会立即终止
- 必须持有订阅返回的
AnyCancellable对象,否则订阅会被提前释放,无法收到任何输出
内容的提问来源于stack exchange,提问作者drekka
相关产品推荐
相关产品推荐

