如何从一系列发布者中创建发布者?

How to make a Publisher from array of Publishers?

我正在使用 Swift Combine 并想制作一个 Publisher,它是从 Publisher 的数组创建的。每当数组中的一个发布者发出一个新元素时,它应该发出一个元素数组。

RxSwift 中会像下面这样:

 let obs1 = PublishSubject<Int>()
 let obs2 = PublishSubject<Int>()
 let arrayObs = [obs1, obs2)]

 Observable.combineLatest(arrayObs)
    .subscribe(onNext: { arrayOfLatest in
        print(arrayOfLatest) //prints an array of integers
    }).disposed(by: disposeBag)

obs1.onNext(5) 
obs2.onNext(10) // prints [5,10]
obs1.onNext(12) // prints [12,10]

只要您不太坚持“数组”部分,combineLatestzip 对于 Combine 框架也是正确的。它们之间的区别在于您是否希望每次发出的总值包含 oldest (zip) 或 newest (combineLatest) 每个出版商的贡献。

您的示例实际上没有提供足够的信息来告诉您需要哪些。要知道你想要哪个,你需要说出当你说时会发生什么,例如:

obs1.onNext(5) 
obs1.onNext(6) 
obs2.onNext(10)

尽管如此,Combine 是Swift,所以它使用元组,而不是数组来表示值的总和。但是,如果像您的示例一样,所有发布者都具有相同的输出和失败类型,则可以轻松地通过映射替换数组。有关将 zip 转换为数组处理器的示例,请参阅 How to zip more than 4 publishers。完全相同的技术适用于 combineLatest.

所以,这是一个实际的工作示例;为了使示例比您的示例更通用,我使用了三个发布者而不是两个:

class ViewController: UIViewController {
    let obs1 = PassthroughSubject<Int,Never>()
    let obs2 = PassthroughSubject<Int,Never>()
    let obs3 = PassthroughSubject<Int,Never>()
    var storage = Set<AnyCancellable>()
    override func viewDidLoad() {
        super.viewDidLoad()
        
        let arr = [obs1, obs2, obs3]
        let pub = arr.dropFirst().reduce(into: AnyPublisher(arr[0].map{[[=11=]]})) {
            res, ob in
            res = res.combineLatest(ob) {
                i1, i2 -> [Int] in
                return i1 + [i2]
            }.eraseToAnyPublisher()
        }
        pub.sink { print([=11=]) }.store(in: &storage)
        obs1.send(5)
        obs2.send(10)
        obs3.send(1) // [5, 10, 1]
        obs1.send(12) // [12, 10, 1]
        obs3.send(20) // [12, 10, 20]
    }
}

使用 combineLatest 非常简单。传下来的值是元组,不是数组。

import Foundation
import Combine

let obs1 = PassthroughSubject<Int, Never>()
let obs2 = PassthroughSubject<Int, Never>()

let sub = obs1.combineLatest(obs2).sink { (first, second) in
    print("\(first) \(second)")
}

obs1.send(5)
obs2.send(10) // prints 5 10
obs1.send(12) // prints 12 10

既然你来自 RxSwift,这个作弊 sheet 可能会有所帮助 https://github.com/CombineCommunity/rxswift-to-combine-cheatsheet