2

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

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返回和可观察的SearchResult 我想循环遍历SearchResult.predictions,获取每个预测的 id 发出请求以requestPlace获取Place附加到数组Places

我希望我的最终数组是

let places = Observable<[Place]> 

或者

let places = [Place]()
4

1 回答 1

2

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

从...开始:

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 { $0 != nil }.map { $0! }

现在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 { $0 != nil }.map { $0! }
    .map { $0.predictions }

我们将需要该函数来再次提取成功对象,因此让我们将其移至单独的函数中:

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

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

let foo = requestPlaceSearch(query: "")
    .map(extractSuccess)
    .filter { $0 != nil }.map { $0! }
    .map { $0.predictions }
    .map { $0.map(requestPlace) }

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

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

这使得 foo a Observable<Observable<[ResultType<Place>]>>. 一个 Observable> 可以很容易地展平。

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

这把 foo 变成了Observable<[ResultType<Place>]>

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

我在上面添加的部分与最后一个返回结果类型的部分相同。此外,此时foo是类型Observable<[Place]>,我们完成了。

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

于 2018-08-15T02:43:41.463 回答