Download and display live market data from API | SwiftUI Crypto App #13
private func fetchData() {
guard let url = URL(string: "https://api.coingecko.com/api/v3/global") else { return }
marketSubscription = NetworkingManager
.download(with: url)
.decode(type: GlobalData.self, decoder: JSONDecoder())
.sink(receiveCompletion: NetworkingManager.handleCompletion,
receiveValue: { [weak self] globalData in
self?.marketData = globalData.data
self?.marketSubscription?.cancel()
})
}
marketDataService
.$marketData
.map(mapGlobalMarketData)
.sink { [weak self] stats in
self?.statistics = stats
}
.store(in: &cancellables)
marketDataSerice
선언marketData
퍼블리셔 구독private func mapGlobalMarketData(marketDataModel: MarketDataModel?) -> [StatisticModel] {
var stats: [StatisticModel] = []
guard let data = marketDataModel else {
return stats
}
let marketCap = StatisticModel(title: "Market Cap", value: data.marketCap, percentageChange: data.marketCapChangePercentage24HUsd)
let volume = StatisticModel(title: "24h Volume", value: data.volume)
let btcDominance = StatisticModel(title: "BTC Dominance", value: data.btcDominance)
let portfolio = StatisticModel(title: "Portfolio Value", value: "$0.00", percentageChange: 0)
stats.append(contentsOf: [marketCap, volume, btcDominance, portfolio])
return stats
}
import Foundation
struct GlobalData: Codable {
let data: MarketDataModel?
}
struct MarketDataModel: Codable {
let totalMarketCap, totalVolume, marketCapPercentage: [String: Double]
let marketCapChangePercentage24HUsd: Double
enum CodingKeys: String, CodingKey {
case totalMarketCap = "total_market_cap"
case totalVolume = "total_volume"
case marketCapPercentage = "market_cap_percentage"
case marketCapChangePercentage24HUsd = "market_cap_change_percentage_24h_usd"
}
var marketCap: String {
if let item = totalMarketCap.first(where: {$0.key == "usd"}) {
return "$" + item.value.formattedWithAbbreviations() }
return ""
}
var volume: String {
if let item = totalVolume.first(where: {$0.key == "usd"}) {
return "$" + item.value.formattedWithAbbreviations()
}
return ""
}
var btcDominance: String {
if let item = marketCapPercentage.first(where: {$0.key == "btc"}) {
return item.value.asPercentString()
}
return ""
}
}
import Foundation
import Combine
class MarketDataService {
@Published var marketData: MarketDataModel?
var marketSubscription: AnyCancellable?
init() {
fetchData()
}
private func fetchData() {
guard let url = URL(string: "https://api.coingecko.com/api/v3/global") else { return }
marketSubscription = NetworkingManager
.download(with: url)
.decode(type: GlobalData.self, decoder: JSONDecoder())
.sink(receiveCompletion: NetworkingManager.handleCompletion,
receiveValue: { [weak self] globalData in
self?.marketData = globalData.data
self?.marketSubscription?.cancel()
})
}
}
import Foundation
import Combine
class HomeViewModel: ObservableObject {
...
@Published var statistics: [StatisticModel] = []
private let coinDataService = CoinDataService()
private let marketDataService = MarketDataService()
private var cancellables = Set<AnyCancellable>()
init() {
addSubscriber()
}
private func addSubscriber() {
// updates allCoins
...
// updates marketData
marketDataService
.$marketData
.map(mapGlobalMarketData)
.sink { [weak self] stats in
self?.statistics = stats
}
.store(in: &cancellables)
}
...
private func mapGlobalMarketData(marketDataModel: MarketDataModel?) -> [StatisticModel] {
var stats: [StatisticModel] = []
guard let data = marketDataModel else {
return stats
}
let marketCap = StatisticModel(title: "Market Cap", value: data.marketCap, percentageChange: data.marketCapChangePercentage24HUsd)
let volume = StatisticModel(title: "24h Volume", value: data.volume)
let btcDominance = StatisticModel(title: "BTC Dominance", value: data.btcDominance)
let portfolio = StatisticModel(title: "Portfolio Value", value: "$0.00", percentageChange: 0)
stats.append(contentsOf: [marketCap, volume, btcDominance, portfolio])
return stats
}
}
[🔥] Bad Response from URL: https://api.coingecko.com/api/v3/global
현재 API 서비스를 제공하는 서버 측 에러로 인해 다운된 상태. 실제 API 호출 대신 가데이터를 리턴하는 형식으로 UI 확인
private func getMockData() {
DispatchQueue.main.asyncAfter(deadline: .now() + 1) { [weak self] in
let totalMarketCap = ["usd": 1054229012066.3087]
let totalVolumne = ["usd": 126545685500.6336]
let marketCapPercentage = [
"btc": 36.998185262325336,
"eth": 17.681382820092026,
"usdt": 6.5831939813084235,
"bnb": 5.1925353562337975,
"usdc": 4.041233854657529,
"xrp": 2.1730297151359728,
"busd": 2.082724887419054,
"doge": 1.7011800098622947,
"ada": 1.316983958634922,
"sol": 1.0798557266066307
]
let marketCapChangePercentage24hUsd = 0.2673890923434678
let marketData = MarketDataModel(totalMarketCap: totalMarketCap, totalVolume: totalVolumne, marketCapPercentage: marketCapPercentage, marketCapChangePercentage24HUsd: marketCapChangePercentage24hUsd)
self?.marketData = marketData
}
}