如何在不覆盖以前数据的情况下使用 rxSwift 压缩、合并或连接?
Posted
技术标签:
【中文标题】如何在不覆盖以前数据的情况下使用 rxSwift 压缩、合并或连接?【英文标题】:How do I zip, merge or concat using rxSwift without overriding previous data? 【发布时间】:2020-10-27 19:08:34 【问题描述】:我想将三个 Observable<[Recipe]>
流合并为一个 Observable<[Recipe]>
。
let breakfast = Database.database().reference().rx.fetchFireBaseData(recipeType: .breakfast)
.map $0.filter UserDefaults.standard.favoriteRecipes.contains($0.fbKey)
let dessert = Database.database().reference().rx.fetchFireBaseData(recipeType: .dessert)
.map $0.filter UserDefaults.standard.favoriteRecipes.contains($0.fbKey)
let cookies = Database.database().reference().rx.fetchFireBaseData(recipeType: .cookies)
.map $0.filter UserDefaults.standard.favoriteRecipes.contains($0.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: $0))
)
我想将accept
的所有组合流映射到behaviorRelay
,映射到cell
数据。然后content
中继是bound
到collectionView
。在观看collectionView
时,使用concat
我可以简要地看到第一个和第二个流,然后将它们替换为最后一个流。
【问题讨论】:
【参考方案1】:您可能不知道,但是 combineLatest(和 zip)有一个用于操作输入的最终参数。所以你可以这样做:
let allRecipes = Observable.combineLatest(breakfast, dessert, cookies) $0 + $1 + $2
相当于:
Observable.combineLatest(breakfast, dessert, cookies)
.map $0.0 + $0.1 + $0.2
这与您最终得到的基本相同,只是您使用 zip
而不是 combineLatest
使用zip
假设所有三个 Observable 将发出完全相同数量的元素。通过使用 combineLatest,您假设每个 Observable 至少发出一个元素,但它们不必都发出相同的数字。
如果您想避免这种假设,请为每个来源添加.startWith
。
Observable.combineLatest(
breakfast.startWith([]),
dessert.startWith([]),
cookies.startWith([])
) $0 + $1 + $2
通过上述方法,只要任何一个源 observable 发出,您就会在输出中得到一些东西,并且每次其他源发出时都会得到另一个更大的数组。
请注意,在上述所有内容(包括您的答案)中,任何一个源 observable 中的错误都会导致整个事情出错。如果你想避免这种情况,你必须在每个源 Observable 上捕获错误。该代码的确切外观取决于您要如何处理这些错误。
【讨论】:
这是一个非常好的解释,非常感谢@Daniel T。【参考方案2】:好的,不知道这是否是最漂亮的解决方法,但我使用了zip
然后只是在compactMap
中将数组相互添加
return Observable.zip(breakfast, dessert, cookies)
.compactMap $0.0 + $0.1 + $0.2
.do(onNext: [weak self] value in
self?.content.accept(value.compactMap FavoritesCollectionViewCellViewModel(favorite: $0))
)
【讨论】:
以上是关于如何在不覆盖以前数据的情况下使用 rxSwift 压缩、合并或连接?的主要内容,如果未能解决你的问题,请参考以下文章
如何在不覆盖之前数据的情况下创建多个 java txt 文件? [复制]
如何在不覆盖的情况下向 Firebase Firestore 添加值?