티스토리 뷰
[암호화폐 거래소 앱 만들기] - SearchBar에 검색어를 입력해 검색 결과를 출력해주는 기능을 구현
B_log 2022. 1. 26. 20:20관련 PR 보러 가기
- [#19] SearchBar에 검색어를 입력해 검색 결과를 출력해주는 기능을 구현해요
회고
SearchBar에서 검색어를 입력하여 코인을 검색하고, 그 검색 결과를 테이블로 보여주는 기능을 구현했어요.
구현 중에 제공되는 API의 모양이 상황에 따라 통일되어있지 않고 상당히 특이하게 되어 있다는 것을 발견해서 PR이 당초 계획보다 비대해졌어요.
그래서 디테일한 요소들은 TBD로 마킹하고 큰 흐름을 구현하는 것에 포인트를 맞췄어요.
작업하면서 생긴 고민들을 작성해볼게요!
API에서 내려받는 데이터에서 발생한 문제
현재 알고 싶은 정보는 API를 통해 검색한 코인 별 정보예요.
우선 호출 URL을 살펴볼게요.
https://api.bithumb.com/public/ticker/{order_currency}_{payment_currency}
order_currency에 원하는 코인 종류를 넣고, payment_currency에 그 코인을 구매하는 통화(KRW, BTC) 기준을 넣어요.
예시를 생각해보면 비트코인을 한국 돈으로 사고 싶다면 BTC_KRW 가 들어가는 구조가 돼요.
그런데 첫 호출에서는 전체를 한 번에 부르는 편이 좋기 때문에 order_currency 자리에 ALL을 넣어야 해요.
당연히 설계할 때 재사용 가능한 메서드를 생각했고, 디코딩 타입을 하나로 생각했어요.
앞의 글에서 date라는 데이터가 들어가서 이 값을 제거해주는 작업을 했는데 이것만으로 문제가 해결된다고 생각했어요.
그런데 문제는 그뿐이 아니었어요.
우선 받아올 데이터의 예시를 살펴볼게요.
// All로 호출 시
{
"status": "0000",
"data": {
"BTC": {
"opening_price": "41369000",
"closing_price": "43738000",
"min_price": "41084000",
"max_price": "45546000",
"units_traded": "4209.25437576",
"acc_trade_value": "183587034224.2125",
"prev_closing_price": "41368000",
"units_traded_24H": "7160.3189384",
"acc_trade_value_24H": "307778152455.7527",
"fluctate_24H": "513000",
"fluctate_rate_24H": "1.19"
},
...
}
}
// 특정 코인으로 검색할 때
{
"status": "0000",
"data": {
"opening_price": "41369000",
"closing_price": "44027000",
"min_price": "41084000",
"max_price": "45546000",
"units_traded": "4530.72099928",
"acc_trade_value": "197702716416.6475",
"prev_closing_price": "41368000",
"units_traded_24H": "6673.65642084",
"acc_trade_value_24H": "287026523345.5483",
"fluctate_24H": "1024000",
"fluctate_rate_24H": "2.38",
"date": "1643101115538"
}
}
단순히 date만 있는 게 문제가 아니라 특정 코인으로 검색할 경우 딕셔너리 형태가 아니라 값 자체만 전달이 돼요.
심지어 그 안에 사용하지도 않을 date가 포함되고요.
특정 코인만 검색하더라도 검색 결과물에 그 코인 종류만 key로 넣어줘도 한 타입 만으로 Decoding이 될 텐데 상황마다 받아오는 데이터의 모양이 너무 달라서 처리하기가 어려웠어요.
혹시나 다른 API가 있거나 변경 가능 여부를 문의하기 위해 빗썸에게 문의를 넣었는데 시간이 지나도 답변이 오지 않았어요.
그래서 나름대로 문제 해결 방법을 설계했어요.
문제 해결하기
우선 Decoding 타입을 한 개로할지, 두 개로 할 지 결정했어요.
struct Model: Decodable {
let status: String
var data: Any
enum CodingKeys: CodingKey {
case status, data
}
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
self.status = try container.decode(String.self, forKey: .status)
if let data = try? container.decode(Datum.self, forKey: .data) {
self.data = data
} else {
self.data = try container.decode([String: Datum].self, forKey: .data)
}
}
}
하나의 Decodable을 사용하는데 분기 처리를 통해 디코딩 타입을 결정해요.
하지만 Any 타입의 사용을 지양하고 싶었고, 사용하더라도 매번 Casting을 통해서 사용해야 하기 때문에 리스크가 있다고 판단했어요.
그래서 2개의 Decodable 타입으로 나누기로 결정했어요.
// 한 번에 검색할 때
struct AllTickerResponse: Decodable {
let status: String
let data: [String: TickerData]
}
struct TickerData: Decodable {
let openingPrice, closingPrice, minPrice, maxPrice: String
let tradedUnit, accTradeValue, previousClosingPrice, tradedUnit24H: String
let accTradeValue24H, fluctate24H, fluctateRate24H: String
let date: String?
enum CodingKeys: String, CodingKey {
case openingPrice = "opening_price"
case closingPrice = "closing_price"
case minPrice = "min_price"
case maxPrice = "max_price"
case tradedUnit = "units_traded"
case accTradeValue = "acc_trade_value"
case previousClosingPrice = "prev_closing_price"
case tradedUnit24H = "units_traded_24H"
case accTradeValue24H = "acc_trade_value_24H"
case fluctate24H = "fluctate_24H"
case fluctateRate24H = "fluctate_rate_24H"
case date
}
}
// 특정 코인만 검색할 때
struct TickerResponse: Decodable {
let status: String
let data: TickerData
}
TickerData를 재활용하기 위해서 Date를 옵셔널로 추가했어요.
이제 Decoding 하는 쪽에서만 데이터 처리가 이루어지면 돼요.
func convertedResponse(orderCurrency: OrderCurrency, data: Data) -> AllTickerResponse? {
if orderCurrency == .all {
return try? JSONDecoder().decode(AllTickerResponse.self, from: data)
}
guard let decodedResponse = try? JSONDecoder().decode(TickerResponse.self, from: data) else { return nil }
return AllTickerResponse(
status: decodedResponse.status,
data: [
orderCurrency.rawValue:TickerData(
openingPrice: decodedResponse.data.openingPrice,
closingPrice: decodedResponse.data.closingPrice,
minPrice: decodedResponse.data.minPrice,
maxPrice: decodedResponse.data.maxPrice,
tradedUnit: decodedResponse.data.tradedUnit,
accTradeValue: decodedResponse.data.accTradeValue,
previousClosingPrice: decodedResponse.data.previousClosingPrice,
tradedUnit24H: decodedResponse.data.tradedUnit24H,
accTradeValue24H: decodedResponse.data.accTradeValue24H,
fluctate24H: decodedResponse.data.fluctate24H,
fluctateRate24H: decodedResponse.data.fluctateRate24H,
date: nil
)
]
)
}
보기 싫은 로직이지만.. key를 어떤 방식으로 넣어줄지 고민이 많았는데요, String 자체를 편집하는 방법이 있지만 데이터를 String으로 편집하는 건 위험성이 있다고 생각했어요. 그래서 코드가 조금 길어지더라도 모든 요소를 매칭 하면서 key를 만드는 방식의 메서드를 생성했어요.
이렇게 하면 오히려 네트워킹의 코드를 깔끔하게 만들 수 있었어요.
switch response.result {
case .success(let data):
guard let data = self.dataToDecode(orderCurrency: orderCurrency, data: data) else { return }
if let response = convertedResponse(orderCurrency: orderCurrency, data: data) {
observer(.success(.success(response)))
} else {
observer(.failure(BithumbNetworkError.decodingError))
}
글이 너무 길어져서 설계와 Rx와 관련된 고민은 다른 글에서 다시 작성할게요 :)
'iOS 앱개발 > 암호화폐 거래소 앱 프로젝트' 카테고리의 다른 글
[암호화폐 거래소 앱 만들기] - 소켓 통신을 통해 코인 정보를 업데이트 하기 (0) | 2022.02.05 |
---|---|
[암호화폐 거래소 앱 만들기] - TableView에서 Cell을 클릭할 경우 다른 화면으로 넘어가기 (0) | 2022.01.30 |
[암호화폐 거래소 앱 만들기] Cell에서 사용할 Coin의 한글 이름을 서버에서 제공하지 않는 문제 해결하기 (0) | 2022.01.26 |
[암호화폐 거래소 앱 만들기] 받아온 데이터에서 원하지 않는 값 제거하기 (0) | 2022.01.26 |
[암호화폐 거래소 앱 만들기] 프로젝트 시작 및 첫 화면 설계하기 (0) | 2022.01.25 |
- Total
- Today
- Yesterday
- 병든 나이트#BOJ#탐욕법#Python
- 배열합치기#분할정복#BOJ#Python
- 섬의개수#백준알고리즘#Python
- NumberofDiscIntersections#Codility#Sort#Python
- 암호코드#dp#BOJ#Python
- 백준 알고리즘#BackTracking
- API#lazy#
- N으로 표현#DP#Programmers#Python
- 종이자르기#분할정복#BOJ#Python
- Triangle#Sorting#Codility#Python
- django
- 날짜 계산#BOJ#완전탐색#Python
- django#slicing
- 파이썬알고리즘인터뷰#4장
- Swift#Tuples#Range
- PassingCars#Codility#Python
- 순열사이클#BOJ#Python
- 터틀비치#리콘#xbox#controller
- 랜선자르기#이분탐색#BOJ#Python
- 리모컨#완전탐색#BOJ#Python
- 공유기 설치#BOJ#이분탐색#Python
- Brackets#Stacks and Queues#Codility#Python
- Distinct#Codility#Python
- 나무자르기#BOJ#이분탐색#Python
- 텀 프로젝트#백준알고리즘#Python
- 반복수열#백준알고리즘#Python
- filter#isalnum#lower
- 쿼드트리#BOJ#분할정복#Python
- 토마토#백준알고리즘#Python
- 미로 탐색#백준알고리즘#Python
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | ||||
4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | 29 | 30 | 31 |