首页 > 解决方案 > 如何从发布者数组中创建发布者?

问题描述

我正在使用 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]

标签: iosswiftreactive-programmingcombine

解决方案


只要您对“数组”部分没有太强烈的坚持,combineLatest或者zip对组合框架也是正确的。它们之间的区别在于您是否希望每次发出的总价值包含来自每个发布者的最旧( zip) 或最新( combineLatest) 贡献。

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

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

尽管如此,Combine 是 Swift,所以它使用元组而不是数组来表达值的整体。但是,如果像您的示例一样,所有发布者都具有相同的输出和失败类型,则可以轻松地通过映射替换数组。请参阅如何压缩 4 个以上的发布zip者,了解如何转换为阵列处理器的示例。完全相同的技术适用于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{[$0]})) {
            res, ob in
            res = res.combineLatest(ob) {
                i1, i2 -> [Int] in
                return i1 + [i2]
            }.eraseToAnyPublisher()
        }
        pub.sink { print($0) }.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]
    }
}

推荐阅读