RxSwift:组合两个网络请求以返回一个值



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

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

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

入手:

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 属于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成为Observable<Observable<[ResultType<Place>]>>.一个可观察的>可以很容易地展平。

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]>类型,我们已完成。

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

最新更新