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) }) }
|