
Download coin details by creating a data model, view model, and API request | SwiftUI Crypto App #19

import Foundation
struct CoinDetailModel: Codable {
    let id, symbol, name: String?
    let blockTimeInMinutes: Int?
    let hashingAlgorithm: String?
    let description: Description?
    let links: Links?
    
    enum CodingKeys: String, CodingKey {
        case id, symbol, name, links, description
        case blockTimeInMinutes = "block_time_in_minutes"
        case hashingAlgorithm = "hashing_algorithm"
    }
}
struct Links: Codable {
    let homepage: [String]?
    let subredditURL: String?
    
    enum CodingKeys: String, CodingKey {
        case homepage
        case subredditURL = "subreddit_url"
    }
}
struct Description: Codable {
    let en: String?
}
Codable 프로토콜에 따르는 구조체func fetchCoinDetails() {
        guard let url = URL(string: "https://api.coingecko.com/api/v3/coins/\(coin.id)?localization=false&tickers=false&market_data=false&community_data=false&developer_data=false&sparkline=true") else { return }
        coinDetailSubscription = NetworkingManager
            .download(with: url)
            .decode(type: CoinDetailModel.self, decoder: JSONDecoder())
            .sink(receiveCompletion: NetworkingManager.handleCompletion,
                  receiveValue: { [weak self] coinDetails in
                self?.coinDetails = coinDetails
                self?.coinDetailSubscription?.cancel()
            })
    }
import Combine
class DetailViewModel: ObservableObject {
    @Published var coinDetails: CoinDetailModel?
    private let coinDetailDataService: CoinDetailDataService
    private var cancellables = Set<AnyCancellable>()
    
    init(coin: CoinModel) {
        self.coinDetailDataService = CoinDetailDataService(coin: coin)
        addSubscriber()
    }
    
    private func addSubscriber() {
        coinDetailDataService
            .$coinDetails
            .sink { [weak self] coinDetails  in
                self?.coinDetails = coinDetails
            }
            .store(in: &cancellables)
    }
}
init(coin: CoinModel) {
        self.coin = coin
        self._viewModel =  StateObject(wrappedValue: .init(coin: coin))
    }
StateObject이기 때문에 WrappedProperty를 초기화하는 방법으로 뷰 모델 이니셜라이즈