실시간 가상화폐 상태를 관측할 수 있는 서비스
현재가 | 실시간 캔들 | 체결 | 호가 | 차트 페이지네이션 |
---|---|---|---|---|
- 최소 버전 : iOS 16.2
- 개발 인원 : 1인
- 개발 기간 : 2024.01.30 ~ 2024.02.12 (2주)
- 업비트 WebSocket 기반 실시간 가상화폐 정보 제공
- 일(Day) 단위 시세 캔들(봉)과 거래량 조회 및 일(Day) 단위 이동평균선(5, 10, 20, 60, 120일) 제공
- 현재가/체결/매도(호가)/매수(호가) 정보 제공
- Swift
- SwiftUI, Combine, Charts
- Clean Architecture, MVVM, Action/State Pattern, Repository Pattern, Router Pattern, Singleton
- Moya
- Async/await, Continuation, URLSessionWebSocketTask
- 관심사의 분리(SoC)를 통해 layer 분리, layer 간의
의존성 규칙
(Dependency Rule) 준수 - SwiftUI + MVVM 구조 기반
Action/State Pattern
적용 - cursor 기반
페이지 네이션
을 통해 이전 캔들(봉), 거래량, 체결 정보 표현 - Combine 기반
데이터 바인딩
및비동기 통신로직
처리 - Moya 기반
Generic request 메서드
구현, MoyaProvider request를 Continuation으로 랩핑해async/await
적용 - URLSessionWebSocketTask 기반
WebSocket 프로토콜 통신
으로실시간 데이터
조회 - 캔들(봉), 거래량, 이동평균선
Charts
활용 구현 - ScrollViewReader, GeometryReader, PreferenceKey를 활용한
Reverse Horizontal Scrollable Chart
구현
- 문제 상황
거래소 화면에서 차트 화면으로 push할 때
// 거래소 Scene
NavigationLink(value: item) {
ExchangeRow(virtualCurrency: item)
}
...
.navigationDestination(for: VirtualCurrency.self) { item in
let viewModel = ChartViewModel(virtualCurrency: item)
ChartView(viewModel: viewModel)
}
차트 화면에서 체결 화면으로 push 할 때
// 차트 Scene
.toolbar {
ToolbarItem(placement: .navigationBarTrailing) {
NavigationLink("체결", value: viewModel.virtualCurrency)
}
}
.navigationDestination(for: VirtualCurrency.self) { item in
let viewModel = TradeViewModel(virtualCurrency: item)
TradeView(viewModel: viewModel)
}
-
문제 원인
VirtualCurrency 타입에 대한 중복된 navigationDestination modifier를 사용한 것이 원인 -
해결 방법
navigationDestination modifier를 사용하지 않고 NavigationLink만 사용해서 해결
거래소 화면에서 차트 화면으로 push할 때
// 거래소 Scene
NavigationLink {
ChartView(viewModel: DIContainer.chartInject(virtualCurrency: item))
} label: {
EmptyView()
}
.opacity(0)
ExchangeRow(virtualCurrency: item, diffItem: viewModel.diffItem)
차트 화면에서 체결 화면으로 push 할 때
// 차트 Scene
.toolbar {
ToolbarItem(placement: .navigationBarTrailing) {
NavigationLink {
TradeView(viewModel: DIContainer.tradeInject(virtualCurrency: viewModel.virtualCurrency))
} label: {
Text("체결")
}
}
}