【问题标题】:How do I zip, merge or concat using rxSwift without overriding previous data?如何在不覆盖以前数据的情况下使用 rxSwift 压缩、合并或连接?
【发布时间】: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 中继是boundcollectionView。在观看collectionView 时,使用concat 我可以简要地看到第一个和第二个流,然后将它们替换为最后一个流。

【问题讨论】:

    标签: ios swift observable concat rx-swift


    【解决方案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)})
    })
    

    【讨论】:

      猜你喜欢
      • 2021-04-18
      • 1970-01-01
      • 2021-11-09
      • 2012-12-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-10-27
      相关资源
      最近更新 更多