嘿,我在HackingWithSwift教程中学到了如何使用Combine发出链式网络请求(参见下面的代码)。现在我将使用RXSwift构建相同的逻辑,但我不知道如何像Combine中那样获取/订阅以获得最终结果。
合并:
//Combine code
func fetch<T: Decodable>(_ url: URL, defaultValue: T) -> AnyPublisher<T, Never> {
let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .iso8601
return URLSession.shared.dataTaskPublisher(for: url)
.retry(1)
.map(\.data)
.decode(type: T.self, decoder: decoder)
.replaceError(with: defaultValue)
.receive(on: DispatchQueue.main)
.eraseToAnyPublisher()
}
//call fetch method and get the end result
fetch(url, defaultValue: [URL]())
.flatMap { urls in
urls.publisher.flatMap { url in
fetch(url, defaultValue: [NewsItem]())
}
}
.collect()
.sink { values in
let allItems = values.joined()
items = allItems.sorted { $0.id > $1.id }
}
.store(in: &requests)
//RXSwift code
func fetchWithRX<T: Decodable>(_ url: URL, defaultValue: T) -> Observable<T> {
let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .iso8601
let request = URLRequest(url: url)
return URLSession.shared.rx.response(request: request)
.retry(1)
.map(\.data)
.decode(type: T.self, decoder: decoder)
.debug()
.catchAndReturn(defaultValue)
.observe(on: MainScheduler.instance)
}
//call fetch2 method
Now I want to subscribe to the values like in the first fetch method with flatMap..collect..sink etc.
fetchWithRX(url, defaultValue: [URL]()) 发布于 2021-03-23 09:14:20
我会这样写这个类比:
fetchWithRX(url, defaultValue: [URL]())
.flatMap { urls in
Observable.zip(urls.map { fetchWithRX($0, defaultValue: [NewsItem]()) })
}
.map { $0.flatMap { $0 }.sorted { $0.id > $1.id } }
.subscribe(onNext: { values in
items = values
})
.disposed(by: requests)这样,我将把所有的逻辑转移到一个map闭包中,这个闭包可以转移到一个用于测试的函数中。尽量减少flatMap或subscribe中的代码量,以提高代码的可测试性。
或者你可以这样写:
fetchWithRX(url, defaultValue: [URL]())
.flatMap { urls in
Observable.zip(urls.map { fetchWithRX($0, defaultValue: [NewsItem]()) })
}
.subscribe(onNext: { values in
let allItems = values.joined()
items = allItems.sorted { $0.id > $1.id }
})
.disposed(by: requests)您可以在本文中了解有关组合可观察对象的更多信息:Recipes for Combining Observables in RxSwift
URLSession还有一个操作符data(request:),它只会发出数据,因此您不必映射即可转储结果对象。如下所示:
func fetchWithRX<T: Decodable>(_ url: URL, defaultValue: T) -> Observable<T> {
let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .iso8601
return URLSession.shared.rx.data(request: URLRequest(url: url))
.retry(1)
.decode(type: T.self, decoder: decoder)
.catchAndReturn(defaultValue)
.observe(on: MainScheduler.instance)
}我突然想到,您可能正在寻找原始组合代码的直接推论……上面的示例将具有相同的最终输出,但它们的工作方式略有不同……
这是一个直接的翻译:
fetchWithRX(url, defaultValue: [URL]())
.flatMap { urls in
// Observable.from(urls) works like urls.publisher
Observable.from(urls).flatMap { url in
fetchWithRX(url, defaultValue: [NewsItem]())
}
}
.toArray() // works like collect(). However, toArray() returns a Single rather than a generic Observable.
.subscribe(onSuccess: { values in
let allItems = values.joined()
items = allItems.sorted { $0.id > $1.id }
})
.disposed(by: requests)不同之处在于,其他示例保留了新闻条目的顺序,而这个示例则不是,因为您无论如何都是在收集和排序,所以最终的输出是相同的。只有在观察输出之前没有使用collect()/toArray()时,才会看到不同之处。
https://stackoverflow.com/questions/66747996
复制相似问题