본문 바로가기
Project/SwiftUI 블록와이드

[SwiftUI Project] 코인 데이터 받아오기 with Combine

by iOS_woo 2022. 9. 13.

Coingecko에서 받아온 250개의 코인리스트

 

데이터를 받아오기 위해 CoinDataService  클라스를 생성합니다.

 

CoinDataService.swift

import Foundation
import Combine

class CoinDataService {
    
    @Published var allCoins: [CoinModel] = []
    
    var coinSubscription: AnyCancellable?
    
    init() {
        getCoin()
    }
    
    private func getCoin() {
        
        guard let url = URL(string: "https://api.coingecko.com/api/v3/coins/markets?vs_currency=usd&order=market_cap_desc&per_page=250&page=1&sparkline=true&price_change_percentage=24h") else { return }
        
        coinSubscription = URLSession.shared.dataTaskPublisher(for: url)
            .subscribe(on: DispatchQueue.global(qos: .default)) // 백그라운드 스레드에서 실행하라. 기본적으로 백그라운드 스레드에서 작업이 되지만 확실히 명시해준다.
            .tryMap { (output) -> Data in
                guard let response = output.response as? HTTPURLResponse,
                      response.statusCode == 200 else {
                          throw URLError(.badServerResponse)
                      }
                return output.data
            }
            .receive(on: DispatchQueue.main) //메인 스레드에서 실행하라
            .decode(type: [CoinModel].self, decoder: JSONDecoder())
            .sink { (completion) in
                switch completion {
                case .finished:
                    break
                case .failure(let error):
                    print(error.localizedDescription)
                }
            } receiveValue: { [weak self] (returnCoins) in
                self?.allCoins = returnCoins
                self?.coinSubscription?.cancel()
            }
    }
}

Combine으로 작성하는 것은 지난 SwiftSoup를 연습할 때 이후로 두번째인데요.

조금더 이해도가 상승한 느낌입니다..!

 

HomeViewModel.swift

import Foundation
import Combine

class HomeViewModel: ObservableObject {
    
    @Published var allCoins: [CoinModel] = []
    @Published var portfolioCoins: [CoinModel] = []
    
    private let dataService = CoinDataService()
    private var cancellables = Set<AnyCancellable>()
    
    init() {
        addSubscribers()
    }
    
    func addSubscribers() {
        dataService.$allCoins //Subcriber
            .sink { [weak self] (returnedCoins) in
                self?.allCoins = returnedCoins
            }
            .store(in: &cancellables)
    }
}

CoinDataService에서 업데이트된 내용을 잘 받을 수 있도록 작성해줍니다. 

 

흐름을 살펴보면 다음과 같습니다. 

 

HomeView -> HomeViewModel -> dataService = CoinDataService()에서 데이터 받아오기 -> $allCoins로 CoinDataService의 allCoins[]를 조회(레퍼런스)하기 -> 참조한 데이터를 HomeViewModel의 allCoins[]에 업데이트 

 

데이터 받아오기 완료! 

댓글