【问题标题】:RxSwift: Combine two network request to return one valueRxSwift:结合两个网络请求返回一个值
【发布时间】:2018-08-15 00:06:01
【问题描述】:

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

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]()

【问题讨论】:

    标签: ios swift rx-swift googleplacesautocomplete


    【解决方案1】:

    我会给你答案,但我会通过解释我是如何得出答案的来引出答案的。希望您能效仿这个过程,并在下一次尝试中自己想出答案。

    开始于:

    let foo = requestPlaceSearch(query: "")
    

    看看foo 的类型是:Observable&lt;ResultType&lt;SearchResult&gt;&gt;。好的,我们需要从结果类型中提取搜索结果。所以...

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

    现在foo 的类型是什么? Observable&lt;SearchResult?&gt;。所以让我们过滤掉可选项。

    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&lt;SearchResult&gt; 所以我们可以取出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 的类型是Observable&lt;[String]&gt;。现在我们有了 ID,我们可以调用另一个端点。

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

    现在foo 的类型为Observable&lt;[Observable&lt;ResultType&lt;Place&gt;&gt;]&gt;。接下来让我们把 [Observable] 变成 Observable。

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

    这使得 foo 成为Observable&lt;Observable&lt;[ResultType&lt;Place&gt;]&gt;&gt;。一个 Observable> 可以很容易地展平。

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

    这会将 foo 变成 Observable&lt;[ResultType&lt;Place&gt;]&gt;

    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&lt;[Place]&gt;,我们就完成了。

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

    【讨论】:

    • 非常感谢您挽救了生命,我已将代码中的最终输出重构为 的可观察值,其中结果是 placeName: Stringplaces: [Place] 的结构体
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多