Issue #451
For some services, we need to deal with separated APIs for getting ids and getting detail based on id.
To chain requests, we can use flatMap and Sequence, then collect to wait and get all elements in a single publish
FlatMap
Transforms all elements from an upstream publisher into a new or existing publisher.
1
| struct FlatMap<NewPublisher, Upstream> where NewPublisher : Publisher, Upstream : Publisher, NewPublisher.Failure == Upstream.Failure
|
Publishers.Sequence
A publisher that publishes a given sequence of elements.
1
| struct Sequence<Elements, Failure> where Elements : Sequence, Failure : Error
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| func fetchItems(completion: @escaping ([ItemProtocol]) -> Void) { requestCancellable = URLSession.shared .dataTaskPublisher(for: topStoriesUrl()) .map({ $0.data }) .decode(type: [Int].self, decoder: JSONDecoder()) .flatMap({ (ids: [Int]) -> AnyPublisher<[HackerNews.Item], Error> in let publishers = ids.prefix(10).map({ id in return URLSession.shared .dataTaskPublisher(for: self.storyUrl(id: id)) .map({ $0.data }) .decode(type: HackerNews.Item.self, decoder: JSONDecoder()) .eraseToAnyPublisher() })
return Publishers.Sequence<[AnyPublisher<HackerNews.Item, Error>], Error>(sequence: publishers) .flatMap({ $0 }) .collect() .eraseToAnyPublisher() }) .receive(on: RunLoop.main) .eraseToAnyPublisher() .sink(receiveCompletion: { completionStatus in switch completionStatus { case .finished: break case .failure(let error): print(error) } }, receiveValue: { items in completion(items) }) }
|