如何使用 rxSwift 压缩、合并或连接而不覆盖以前的数据?
How do I zip, merge or concat using rxSwift without overriding previous data?
我有三个 Observable<[Recipe]>
流,我想将它们合并为一个流 Observable<[Recipe]>
。
let breakfast = Database.database().reference().rx.fetchFireBaseData(recipeType: .breakfast)
.map { [=10=].filter { UserDefaults.standard.favoriteRecipes.contains([=10=].fbKey) }}
let dessert = Database.database().reference().rx.fetchFireBaseData(recipeType: .dessert)
.map { [=10=].filter { UserDefaults.standard.favoriteRecipes.contains([=10=].fbKey) }}
let cookies = Database.database().reference().rx.fetchFireBaseData(recipeType: .cookies)
.map { [=10=].filter { UserDefaults.standard.favoriteRecipes.contains([=10=].fbKey) }}
如果我使用Observable.zip(breakfast, dessert, cookies).do(onNext: { [weak self] value in...
我得到 ([Recipe], [Recipe], [Recipe])
如果我使用Observable.merge(breakfast, dessert, cookies).do(onNext: { [weak self] value in...
我依次获取流,这意味着最后一个完成的会覆盖前两个。
如果我使用Observable.concat(breakfast, dessert, cookies).do(onNext: { [weak self] value in...
我得到了与 merge
.
相同的行为
那么如何将三个流合并为一个流而不让它们相互覆盖?
为了更好地了解我要做什么:
return Observable.merge(breakfast, cookies, dessert).do(onNext: { [weak self] value in
self?.content.accept(value.compactMap { FavoritesCollectionViewCellViewModel(favorite: [=11=])})
})
我想 accept
所有组合流到 behaviorRelay
,映射到 cell
数据。然后 content
中继 bound
到 collectionView
。观看 collectionView
时,使用 concat
我可以短暂地看到第一和第二个流,然后它们被最后一个流替换。
好的,不知道这是否是解决它的最漂亮的方法,但我使用了 zip
然后只是在 compactMap
中将数组彼此相加
return Observable.zip(breakfast, dessert, cookies)
.compactMap { [=10=].0 + [=10=].1 + [=10=].2 }
.do(onNext: { [weak self] value in
self?.content.accept(value.compactMap { FavoritesCollectionViewCellViewModel(favorite: [=10=])})
})
您可能不知道,combineLatest(和 zip)有一个用于处理输入的最终参数。所以你可以这样做:
let allRecipes = Observable.combineLatest(breakfast, dessert, cookies) { [=10=] + + }
相当于:
Observable.combineLatest(breakfast, dessert, cookies)
.map { [=11=].0 + [=11=].1 + [=11=].2 }
这与你最终得到的基本相同,除了你使用 zip
而不是 combineLatest
使用zip
假设所有三个 Observable 将发出完全相同数量的元素。通过使用 combineLatest,您假设每个 Observable 至少发射一个元素,但它们不必都发射相同的数字。
如果您想避免这种假设,请为每个来源添加一个 .startWith
。
Observable.combineLatest(
breakfast.startWith([]),
dessert.startWith([]),
cookies.startWith([])
) { [=12=] + + }
有了上面的内容,只要任何一个源 observable 发出,您就会在输出中得到一些东西,并且每次其他发出时都会得到另一个更大的数组。
请注意,在以上所有内容(包括您的回答)中,任何一个源可观察对象中的错误都会导致整个事情出错。如果你想避免这种情况,你将不得不捕获每个源 Observable 的错误。该代码的确切外观取决于您要对错误执行的操作。
我有三个 Observable<[Recipe]>
流,我想将它们合并为一个流 Observable<[Recipe]>
。
let breakfast = Database.database().reference().rx.fetchFireBaseData(recipeType: .breakfast)
.map { [=10=].filter { UserDefaults.standard.favoriteRecipes.contains([=10=].fbKey) }}
let dessert = Database.database().reference().rx.fetchFireBaseData(recipeType: .dessert)
.map { [=10=].filter { UserDefaults.standard.favoriteRecipes.contains([=10=].fbKey) }}
let cookies = Database.database().reference().rx.fetchFireBaseData(recipeType: .cookies)
.map { [=10=].filter { UserDefaults.standard.favoriteRecipes.contains([=10=].fbKey) }}
如果我使用Observable.zip(breakfast, dessert, cookies).do(onNext: { [weak self] value in...
我得到 ([Recipe], [Recipe], [Recipe])
如果我使用Observable.merge(breakfast, dessert, cookies).do(onNext: { [weak self] value in...
我依次获取流,这意味着最后一个完成的会覆盖前两个。
如果我使用Observable.concat(breakfast, dessert, cookies).do(onNext: { [weak self] value in...
我得到了与 merge
.
那么如何将三个流合并为一个流而不让它们相互覆盖?
为了更好地了解我要做什么:
return Observable.merge(breakfast, cookies, dessert).do(onNext: { [weak self] value in
self?.content.accept(value.compactMap { FavoritesCollectionViewCellViewModel(favorite: [=11=])})
})
我想 accept
所有组合流到 behaviorRelay
,映射到 cell
数据。然后 content
中继 bound
到 collectionView
。观看 collectionView
时,使用 concat
我可以短暂地看到第一和第二个流,然后它们被最后一个流替换。
好的,不知道这是否是解决它的最漂亮的方法,但我使用了 zip
然后只是在 compactMap
return Observable.zip(breakfast, dessert, cookies)
.compactMap { [=10=].0 + [=10=].1 + [=10=].2 }
.do(onNext: { [weak self] value in
self?.content.accept(value.compactMap { FavoritesCollectionViewCellViewModel(favorite: [=10=])})
})
您可能不知道,combineLatest(和 zip)有一个用于处理输入的最终参数。所以你可以这样做:
let allRecipes = Observable.combineLatest(breakfast, dessert, cookies) { [=10=] + + }
相当于:
Observable.combineLatest(breakfast, dessert, cookies)
.map { [=11=].0 + [=11=].1 + [=11=].2 }
这与你最终得到的基本相同,除了你使用 zip
而不是 combineLatest
使用zip
假设所有三个 Observable 将发出完全相同数量的元素。通过使用 combineLatest,您假设每个 Observable 至少发射一个元素,但它们不必都发射相同的数字。
如果您想避免这种假设,请为每个来源添加一个 .startWith
。
Observable.combineLatest(
breakfast.startWith([]),
dessert.startWith([]),
cookies.startWith([])
) { [=12=] + + }
有了上面的内容,只要任何一个源 observable 发出,您就会在输出中得到一些东西,并且每次其他发出时都会得到另一个更大的数组。
请注意,在以上所有内容(包括您的回答)中,任何一个源可观察对象中的错误都会导致整个事情出错。如果你想避免这种情况,你将不得不捕获每个源 Observable 的错误。该代码的确切外观取决于您要对错误执行的操作。