블록와이드에 CoinGecko RestAPI로 받아오던 코인 정보를 업비트 RestAPI를 활용해 교체하려는 시도를 했습니다.
결과적으로는 성공하였습니다.
하지만 그리 만족스럽지는 못했는데요.
지금까지 작업한 코드는 아래와 같습니다.
import Foundation
import Alamofire
import Combine
class UpbitCoinDataService {
@Published var coins = [UpbitCoin]()
@Published var tickers = [UpbitTicker]()
private let baseUrl = "https://api.upbit.com/v1"
private var cancellables = Set<AnyCancellable>()
init() {
fetchCoins()
}
private func fetchCoins() {
AF.request("\(baseUrl)/market/all")
.validate(statusCode: 200..<300)
.publishDecodable(type: [UpbitCoin].self, decoder: JSONDecoder())
.compactMap { $0.value }
.map { $0.filter { $0.market.hasPrefix("KRW") } }
.sink(receiveCompletion: { completion in
switch completion {
case .failure(let error):
print("Error fetching upbit coins: \(error)")
case .finished:
print("Upbit coin data fetching finished.")
self.fetchTickers()
}
}, receiveValue: { [weak self] coins in
self?.coins = coins
})
.store(in: &cancellables)
}
func fetchTickers() {
let tickersUrl = "https://api.upbit.com/v1/ticker?markets=" + coins.map { $0.market }.joined(separator: ",")
AF.request(tickersUrl)
.validate(statusCode: 200..<300)
.publishDecodable(type: [UpbitTicker].self, decoder: JSONDecoder())
.compactMap { $0.value }
.sink(
receiveCompletion: { completion in
switch completion {
case .failure(let error):
print("Error fetching upbit tickers: \(error)")
case .finished:
print("Upbit ticker data fetching finished.")
// print(self.tickers.first(where: { $0.market == "KRW-BTC" }))
}
},
receiveValue: { [weak self] tickers in
self?.tickers = tickers
}
)
.store(in: &cancellables)
}
}
fetchCoins를 통해 업비트에 상장되어 있는 KRW 마켓의 코인목록을 받아오고,
목록을 기반으로 가격, 변동률, 거래량 등의 구체적인 데이터를 fetchTickers로 받아오는 순서였습니다.
주식, 코인 어플에서 제공하는 화면처럼 실시간으로 데이터를 바꿔주기 위해서 아래와 같이 1초마다 fetchTickers를 호출하였고,
이를 뷰에 뿌려주었습니다.
func fetchTickersWithInterval() {
var tickerTimer: AnyCancellable?
$isTimerRunning
.sink { [weak self] isTimerRunning in
tickerTimer?.cancel()
if isTimerRunning {
tickerTimer = Timer.publish(every: 1, on: .main, in: .common)
.autoconnect()
.sink { [weak self] _ in
self?.dataService.fetchTickers()
}
}
}
.store(in: &cancellables)
}
결과는 어떻게 되었을까요?
결과적으로는 1초마다 데이터가 갱신되었지만 문제가 조금 있었습니다.

앱을 사용할 때 1초마다 버벅이는 문제가 생겼습니다.
예를 들어 리스트를 스크롤해서 위로 올리면 툭툭 끊기면서 올라갑니다.
fetchTickersWithInterval() 함수가 실행되는 조건을 만들어서 유저가 스크롤을 할 때에는 네트워크 작업을 하지 못하게 하거나,
뷰가 사라지면 네트워크 작업을 하지 않는다거나... 등의 작업을 해주었습니다.
덕분에 유저가 앱을 만지고 탐색할 때에는 버벅이는 현상이 줄어들었습니다.
하지만 곰곰히 생각해보니 이런 식으로 향후 기능이 추가될 때마다 이러한 조건부 작업을 해줘야 한다고 생각하니..
여간 번거로운 작업이 아닐 수 없었고, 생각보다 버벅이는게 거슬린다는 문제가 있습니다.
그래서 이것저것 자료를 찾아보던 중 업비트에서 제공하는 WebSocket에 대해서 알아보고 있습니다.
Rest API는 한번 요청하면 응답도 한번 해줍니다.
저는 이런 Rest API를 1초마다 100여개의 모든 코인에 대해서 매번 요청을 하는 것이었고, 매번 가격이 변하는 것도 아니어서 자원의 낭비가 굉장히 큰 형식이었습니다.
하지만 WebSocket은 한번 요청하면 채널이 형성되어서 끊기 전까지 관련 데이터를 업데이트 해준다고 합니다.
주로 스트리밍, 실시간 채팅, 주식과 코인 데이터를 갱신하는 기능에서 많이 사용된다고 하네요.
WebSocket에 대해서 이리저리 찾아보다보니 아직 완벽하게 이해되지는 않지만
활용하면 RestAPI를 몇 초에 한번씩 고반복으로 요청하는 것보다 훨씬 효율적일 것이라 생각이 들어서 공부를 해보려고 합니다.
업비트 채용 공고에서도 WebSocket 사용 경험에 대해서 언급하고 있기도 하고,
확실하게 익혀두면 향후 앱에 추가될 실시간 채팅 기능이나 코인 데이터 등 Rest API를 활용 할 때와 또 다른 유용함이 있을 것 같아요.
WebSocket에 대해서 정리가 되면 블로그에도 글을 남기겠습니다. :)
'Project > SwiftUI 블록와이드' 카테고리의 다른 글
URLSessionWebSocketTask로 업비트 WebSocket (웹소켓) 사용하기 (0) | 2023.03.09 |
---|---|
블록와이드 1.1.4 업데이트 소식 (0) | 2023.02.27 |
[블록와이드] 뉴스 검색 기능 추가, 보완하고 싶은 점 (0) | 2023.02.14 |
[블록와이드] 뉴스 키워드 편집 기능 추가 (0) | 2023.02.11 |
[SwiftUI] @AppStorage로 배열(Array) 다루기 (0) | 2023.02.05 |
댓글