RxSwift 中的链式请求使用第一个请求来设置更多请求,然后 return 全部完成

Chain requests in RxSwift using first request to setup further requests then return all when complete

我有一个要求 Article

每个 Article 包含一个 ArticleAsset 的数组,其中包含渲染整篇文章时我需要的各种道具。

我事先不知道一篇文章有​​多少资产,所以我必须请求这篇文章,然后使用 assets prop dispatch X amount of request 到 return 的值每个 ArticleAsset.

到那时我应该 return 我的资产提取的文章和结果数组。

为简单起见,假设在这种情况下每个资产 return 都是 Int。所以我从这个开始 -

Article > [Article]

我希望最终得到如下形状的元组 (article: Article, assets: [Int])

我试图将其重新创建为下面的游乐场,但完全没有成功,有点卡住了。

我了解如何使用 flatMapLatest 等链接固定数量的请求,但在这种情况下我不知道请求的数量。我在想我应该为每个 ArticleAsset 和 return 映射一个 Observables 的数组,但是我开始对下一步要去哪里感到非常模糊。

如有任何帮助,我们将不胜感激,谢谢。

import UIKit
import RxSwift

private let disposeBag = DisposeBag()

struct Article {
       let id: UUID = UUID()
       var assets: [ArticleAsset]
   }

   struct ArticleAsset {
       let number: Int
   }

   let assets: [ArticleAsset] = Array(0...4).map { ArticleAsset(number: [=11=]) }
   let article = Article(assets: assets)

   func fetchArticle() -> Observable<Article> {
       return Observable.of(article)
   }

   func getArticleAsset(asset: ArticleAsset) -> Observable<Int> {
       return .of(asset.number)
   }

   fetchArticle()
       .map { art in
           let assets = art.assets.map { getArticleAsset(asset: [=11=]) }
           let resp = (article: art, assets: Observable.of(assets))
           return resp
   }.subscribe(onNext: { resp in

     // I would like my subscriber to receive (article: Article, assets: [Int])

   }).disposed(by: disposeBag)

Rx 有几个扁平化运算符。 flatMapLatest 不是你想要的,因为它只会给你最后一个内部观察的结果。您真正想要的是合并所有 ArticleAsset 流,并仅在它们全部完成后才继续。因此,您想 merge 所有 ArticleAsset 请求,然后 reduce 将它们放入 ArticleAsset 数组中。

fetchArticle()
  .flatMap { article in 
     let allAssetRequests = article.assets.map {
      getArticleAsset(asset: article)
     }
     return Observable
       .merge(allAssetRequests)
       .reduce([ArticleAsset]()) { array, asset in
          //Combine here
       }
  }

您可以在此处更改 reduce 以缩减为一个元组:(Article, [ArticleAsset]) 然后您将获得您要查找的流的最终形式。

制作可编译游乐场的荣誉!这让事情变得容易多了。你想在这里做的是结合可观察量。 In my article 你会发现有很多方法可以做到这一点。我认为对于这个用例,zip 运算符是最好的。

let articleWithAssets = fetchArticle()
    .flatMap { (article) -> Observable<(article: Article, assets: [Int])> in
        let articles = Observable.zip(article.assets.map { getArticleAsset(asset: [=10=]) })
        return Observable.zip(Observable.just(article), articles) { (article: [=10=], assets: ) }
    }

articleWithAssets
    .subscribe(onNext: { resp in
        // here `resp` is of type `(article: Article, assets: [Int])` as requested.
    })

fetchArticle()发出一个值时,flatMaps闭包将被调用,它会为每个资产调用getArticleAsset(asset:),等到它们全部完成,将它们组合成一个单个 Observable 数组(articles 对象),然后将其与 .just(article) observable 组合。

警告,如果任何 one 资产请求失败,则整个链都会失败。如果你不想要那个,你将不得不在 { getArticleAsset(asset: [=17=]) } 块中处理它。 (也许会发出 nil 或 missingAsset 资产。)