如何从一系列发布者中创建发布者?
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]
只要您不太坚持“数组”部分,combineLatest
或 zip
对于 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
我正在使用 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]
只要您不太坚持“数组”部分,combineLatest
或 zip
对于 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