각 국가 환율별 비트코인 1개당 시세를 알려주는 앱을 만들어 보았다.
이때까지 적용해 본 MVC 디자인 패턴, API 통신, Delegate Design Pattern, 그리고 JSON 파싱을 종합적으로 적용을 해야 하는 앱이라서 조금 복잡한 감이 없지 않아 있었다.
어떤 화폐 단위를 선택하느냐에 따라 상위에 나타나는 레이블이 실시간으로 변할 수 있도록 제작하였고, 개인 API key 를 발급받아 API 통신을 구현하였다.
우선 Main.storyboard 를 위와 같이 구성하였다. 두드러진 특징은 없지만 이번에 처음으로 UIPickerView를 적용해보았다.
MVC 디자인 패턴에 따라 Model, View, Controller 파일을 분리해주었다.
우선 국가 환율에 따라 비트코인 시세 정보를 실시간으로 받아오기 위해서는
CoinAPI 사이트에 접속해서 개인 API Key 를 발급받아야 한다. 회원가입을 하고 개인 이메일 정보를 제공하면 몇 분 내로 개인 API key 가 발급됐다고 이메일이 날라온다.
해당 사이트의 API documents 를 살펴보면 어떻게 request 를 보내는지 상세히 나와있다. 어떤 정보를 가지고 오고 싶은지에 따라 방법이 다양한데, 나 같은 경우에는 current rate 를 받고 싶기에 거기에 맞춰서 내용을 읽었다.
위 링크 형식으로 요청을 보내야 하는데, 밑줄 쳐놓은 부분들이 개발자인 내가 API 통신을 위해서 별도로 입력해야 하는 값들이다.
USD 는 미국 달러를 이야기하고, 유로면 EUR, 이런 식으로 쿼리값을 보내야한다. apikey 는 앞서 발급받은 개인 API Key 를 이야기한다.
올바른 링크 형식으로 요청을 작성하고 엔터를 누르면 위 사진과 같은 JSON object가 표시된다. 여기서 필요한 정보는 대략 asset_id_quote 과 rate 정도가 될 것 같다.
rate 값이 31815.8859.. 로 되어 있는데 이는 비트코인 1개당 $31815 라는 것이다. (엄청 비싸네..)
앱에서 받아야 하는 데이터를 정했으니, 그에 맞는 구조체를 선언해준다. 파일명만 봐도 알기 쉽게 CoinData 라는 이름으로 파일을 만들었고, 적절하게 구조체를 선언해주었다.
개발을 하다가 중간에 해당 구조체가 Codable 프로토콜을 채택해야 함을 까먹어서 나중에 어디서 문제가 있는건지 찾느라 애를 좀 먹었다.
CoinModel 이라는 구조체도 따로 선언해주었는데, 이 구조체는 API 통신을 하고 정보를 받아올 때, 즉 decoding 할 때 사용하는 구조체가 아니라, 이미 받아온 정보를 또 따로 적합하게 저정할 수 있도록 도와주는 구조체다.
이제 CoinManager.swift 파일이다. 우선 Delegate Design Pattern 을 나름 적용할 것이기 때문에 프로토콜을 정의해준다. 해당 프로토콜에는 코인의 시세가 정상적으로 업데이트가 됐음을 알릴 수 있는 didUpdateCoinRate 메서드와 에러가 났을 때를 위한 didFailWithError 메서드를 정의하였다.
CoinManager 구조체에는 baseURL, apiKey 상수와 가지고 오고자 하는 국가 환율 단위가 저장되어 있는 배열을 선언하였다. 추가로 맨 처음에 정의한 CoinManagerDelegate 타입의 변수 delegate 도 선언하여 이후에 ViewController 에서 인스턴스를 생성했을 때 프로토콜을 구현할 수 있도록 하였다.
getCoinPrice 는 사용자가 UIPickerView 에서 항목을 선택했을 때 수행된다. 이때 performRequest 함수도 동시에 실행된다.
performRequest() 함수는 이전 날씨 앱 포스팅의 내용과 거의 흡사하다. 네트워킹을 위해서 아래와 같은 4단계가 필요하며, 이를 performRequest() 함수에 정의하였다.
parseJSON 함수에서는 받아오고자 하는 데이터를 별도의 상수로 하나하나 받고, 이를 CoinModel 타입으로 묶어주었다.
마지막으로 ViewController 파일이다. 우선 UIPickerView 를 제대로 활용하기 위해서는 ViewController 클래스가 UIPickerViewDataSource 과 UIPickerViewDelegate 프로토콜을 채택하도록 해야 한다. 위 사진에서는 안 나와 있고 가독성 향상을 위해 모두 extension 으로 빼놓은 상태다. 두 프로토콜을 채택하면 각 프로토콜의 delegate 을 설정해야 하는데, 이를 모두 self 로 정의하였다. 즉, ViewController 클래스가 프로토콜 구현하는 임무를 받겠다는 이야기다.
이렇게 delegate 를 설정하는 것도 쉽게 까먹을 수 있을 것 같다.나도 나중에 3개를 모두 설정해야하는 것을 까먹고 앱을 실행해보았는데 안 돼서 당황한 적이 있다.
UIPickerViewDataSource 프로토콜을 구현하는 extension 부분이다. 여기서 numberOfComponents 는 UIPickerView 가 몇 개의 열(column)이 필요한지 정의해준다. 본인 앱에서는 1개만 필요하니 바로 return 1 으로 작성해주었다.
pickerView () 함수는 얼핏보면 무엇을 하는 함수인지 잘 모르겠지만, 내부 파라미터를 보면 numberOfRowsInComponent 라는 파라미터가 있다. 즉, 행(rows) 이 총 몇 개 필요한지 쓰라는 것이다. 따로 몇 개인지 하나하나 셀 수는 없으니 아까 만들어둔 배열의 .count 를 반환하였다.
위는 UIPickerViewDelegate 프로토콜을 구현하는 extension이다.
첫 번째 함수 pickerView 는 방금의 함수와 이름은 비슷하지만 내부 파라미터가 거의 다르다는 것을 알 수 있다. titleForRow 가 핵심인데, 이 함수에서는 각 Row 의 title 을 String 타입으로 정의하라는 것이다. 간단하게 아까 만들어둔 String 타입 배열을 인덱스로 접근할 수 있도록 정의하였다.
두 번째 함수는 didSelectRow 를 보면 된다. 즉, 유저가 각 row 를 선택했을 때 어떤 일이 발생해야하는지 정의해주면 된다. 우리는 유저가 각 row 를 선택했을 때마다 비트코인의 시세를 표시해야 하기 때문에 바로 coinManager 인스턴스가 getCoinPrice() 를 실행해주도록 한다. 여기서 performRequest(), parseJSON() 등의 메서드가 한 방에 실행이 된다.
CoinManager 의 performReqeust()가 실행되면 delegate 보고 didUpdateCointRate() 또는 didFailWithError() 역시 실행할 수 있도록 아까 정의하였다. 즉, API 통신을 통해서 제대로 코인 시세 정보를 받아왔다면 ViewController 에 연결된 IBOutlet 들의 text가 바뀔 수 있도록 코드를 작성해주었다.
이렇게 각 국가 환율별 비트코인 1개당 시세를 알려주는 앱을 만들어 보았다. 별거 아닌 앱이지만 API 통신을 연습하고, MVC 디자인 패턴과 Delegate Design Pattern 을 살짝 적용해 볼 수 있어 좋은 연습이 된 것 같다.