Skip to content

Instantly share code, notes, and snippets.

@djrobby
Forked from rhys-rant/CombinePokemonAPI.swift
Created July 13, 2020 21:03
Show Gist options
  • Save djrobby/76c3cf0a2d90441b47f5933f24d35716 to your computer and use it in GitHub Desktop.
Save djrobby/76c3cf0a2d90441b47f5933f24d35716 to your computer and use it in GitHub Desktop.
import Combine
import Foundation
struct NamedURL: Codable {
let name: String
let url: URL
}
struct PokeAPIResponse: Codable {
let results: [NamedURL]
}
struct Pokemon: Codable {
let id: Int
let name: String
let stats: [Stat]
let weight: Double
}
struct Stat: Codable {
let baseStat: Int
let effort: Int
let stat: NamedURL
enum CodingKeys: String, CodingKey {
case baseStat = "base_stat"
case effort
case stat
}
}
class PokemonGetter: ObservableObject {
@Published var pokemon: [Pokemon] = [] {
didSet {
print("Pokémon list updated!")
for pokemon in pokemon {
print("Pokémon \(pokemon.id): \(pokemon.name)")
}
}
}
private let apiURL = URL(string: "https://pokeapi.co/api/v2/pokemon")!
let jsonDecoder = JSONDecoder()
private var subscription: AnyCancellable?
func start() {
print("Starting...")
if subscription != nil {
subscription?.cancel()
}
subscription = URLSession.shared.dataTaskPublisher(for: apiURL)
.map(\.data)
.decode(type: PokeAPIResponse.self, decoder: jsonDecoder)
.flatMap { response in
Publishers.MergeMany(
response.results.map(self.namedResourceGetter)
)
.collect()
}
.replaceError(with: [Pokemon(id: 999, name: "Error", stats: [], weight: 100)])
.sink { pokemon in
self.pokemon = pokemon.sorted(by: { $0.id < $1.id })
}
}
private func namedResourceGetter(_ namedURL: NamedURL) -> AnyPublisher<Pokemon, Error> {
URLSession.shared.dataTaskPublisher(for: namedURL.url)
.map { $0.data }
.decode(type: Pokemon.self, decoder: jsonDecoder)
.eraseToAnyPublisher()
}
}
let pokemonGetter = PokemonGetter()
pokemonGetter.start()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment