RxSwift:将两个网络请求合并为 return 个值

RxSwift: Combine two network request to return one value

我有两个网络请求,我想将结果合并到一个对象数组中。

enum ResultType<T> {
  case success(T)
  case failure(Error)
}

static func requestPlaceSearch(query: String) -> Observable<ResultType<SearchResult>> {
    let urlString = "https://maps.googleapis.com/maps/api/place/autocomplete/json"
    let params = ["input": query, "types": "geocode",
                "key": "key"]
    return placeRequest(url: urlString, params: params)
}

static func requestPlace(with placeId: String) -> Observable<ResultType<Place>> {
    let params = ["placeid": placeId, "key": "key"]
    let urlString = "https://maps.googleapis.com/maps/api/place/details/json"
    return placeRequest(url: urlString, params: params)
}

requestPlaceSearch returns 和 SearchResult 的可观察性 我想遍历 SearchResult.predictions,获取每个预测的 ID 请求 requestPlace 获取 Place 并附加到 Places

的数组

我希望我的最终数组是

let places = Observable<[Place]> 

let places = [Place]()

我会给你答案,但我会通过解释我是如何得出答案的来把它画出来的。希望您可以模拟这个过程,并在下一次尝试中自己得出答案。

开始于:

let foo = requestPlaceSearch(query: "")

然后查看 foo 的类型,即:Observable<ResultType<SearchResult>>。好的,我们需要从结果类型中提取搜索结果。所以...

let foo = requestPlaceSearch(query: "")
    .map { (result: ResultType<SearchResult>) -> SearchResult? in
        if case let .success(search) = result {
            return search
        } else {
            return nil
        }
    }

现在foo的类型是什么? Observable<SearchResult?>。所以让我们过滤掉选项。

let foo = requestPlaceSearch(query: "")
    .map { (result: ResultType<SearchResult>) -> SearchResult? in
        if case let .success(search) = result {
            return search
        } else {
            return nil
        }
    }
    .filter { [=12=] != nil }.map { [=12=]! }

现在 foo 的类型是:Observable<SearchResult> 所以我们可以提取 predictions.

let foo = requestPlaceSearch(query: "")
    .map { (result: ResultType<SearchResult>) -> SearchResult? in
        if case let .success(search) = result {
            return search
        } else {
            return nil
        }
    }
    .filter { [=13=] != nil }.map { [=13=]! }
    .map { [=13=].predictions }

我们将需要该函数再次提取成功对象,所以让我们将其移至一个单独的函数中:

func extractSuccess<T>(_ result: ResultType<T>) -> T? {
    if case let .success(search) = result {
        return search
    } else {
        return nil
    }
}

我假设 predictions 只是字符串。您可能必须从中提取字符串 ID。所以现在 foo 的类型是 Observable<[String]>。现在我们有了 ID,我们可以调用另一个端点。

let foo = requestPlaceSearch(query: "")
    .map(extractSuccess)
    .filter { [=15=] != nil }.map { [=15=]! }
    .map { [=15=].predictions }
    .map { [=15=].map(requestPlace) }

现在 fooObservable<[Observable<ResultType<Place>>]> 类型。接下来让我们把 [Observable] 变成 Observable<[T]>.

let foo = requestPlaceSearch(query: "")
    .map(extractSuccess)
    .filter { [=16=] != nil }.map { [=16=]! }
    .map { [=16=].predictions }
    .map { Observable.combineLatest([=16=].map(requestPlace)) }

这使得 foo 成为 Observable<Observable<[ResultType<Place>]>>。 Observable> 可以很容易地展平。

let foo = requestPlaceSearch(query: "")
    .map(extractSuccess)
    .filter { [=17=] != nil }.map { [=17=]! }
    .map { [=17=].predictions }
    .flatMap { Observable.combineLatest([=17=].map(requestPlace)) }

将 foo 变成 Observable<[ResultType<Place>]>

let foo = requestPlaceSearch(query: "")
    .map(extractSuccess)
    .filter { [=18=] != nil }.map { [=18=]! }
    .map { [=18=].predictions }
    .flatMap { Observable.combineLatest([=18=].map {
        requestPlace(with: [=18=])
            .map(extractSuccess)
            .filter { [=18=] != nil }.map { [=18=]! }
        })
    }

我在上面添加的部分与上一个returns结果类型相同。另外,此时 fooObservable<[Place]> 类型,我们就完成了。

请注意,此代码不处理任何失败结果。我将把它留作 reader 的练习。 :-)