swift로 코인 앱 만들기 Part1. Coins
본문에 들어가기에 앞서, 이번 앱은 Nomad Coders에서 제공하는 챌린지 프로그램인 React Native 챌린지에서 나온 앱(Coin Tracker였나?)인데, React Native로 만든 앱은 아니고, 제목에 썼다시피 필자가 스스로 Swift로 재구성(?)해서 만든 앱이다.
Nomad Coders에는 챌린지 내용 공유 금지가 있지만 이 앱은 Swift로 만든 앱으로 Nomad Coders에서는 제공하지 않는 프로그래밍 언어이기에 운영자님께 Swift면 괜찮다고 해서 이 앱을 포스팅 한다.
서두가 길었다. 시작한다.
앱의 구성부터
(이미지가 좀 크네... 출처는 Doeveloper님의 챌린지 우수작 결과물로부터)
총 4개의 Tab bar navigation으로 이루어진 앱이며, 각각 코인 목록과 Detail, 코인 가격, 코인 관련 뉴스, Discover(뭐하는 건지는 모르겠다. 1기 챌린지를 하다 말아서...)로 구성되어 있다.
맨 처음부터 차례대로 만들어 보기로 한다.
Storyboard 구성
... 안 보이쥬?
시작은 일단 Tab Bar Controller로 시작한다.
여기에서 네 개의 화면으로 뻗어나간다.
Coins 화면
Navigation Controller - View Controller - View Controller(Detail)로 구성되어 있다.가운데는 위의 스샷에서 보는것 처럼 코인 목록을 rank순으로 row당 3개씩 보여주는 Collection View Controller다.
소스
import UIKit
import Alamofire
import Kingfisher
class CoinsViewController: UICollectionViewController {
@IBOutlet weak var indicator: UIActivityIndicatorView!
var cellsPerRow: CGFloat = 3
let cellMargin: CGFloat = 10
var coins: [Coin] = [] {
didSet {
collectionView.reloadData()
}
}
override func viewDidLoad() {
super.viewDidLoad()
let nibName = UINib(nibName: "CoinCell", bundle: nil)
collectionView.register(nibName, forCellWithReuseIdentifier: "CoinCell")
self.indicator.startAnimating()
self.fetchCoinsData(completionHandler: { [weak self] result in
guard let self = self else { return }
self.indicator.stopAnimating()
self.indicator.isHidden = true
switch result {
case let .success(result):
self.coins = result
case let .failure(error):
debugPrint("Error: \(error)")
}
})
}
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return coins.count
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CoinCell", for: indexPath) as? CoinCell else { return UICollectionViewCell() }
let imageURL = URL(string: "https://cryptoicon-api.vercel.app/api/icon/\(coins[indexPath.item].symbol.lowercased())")
cell.coinSymbolLabel.text = coins[indexPath.item].name
cell.coinSymbolImageView.kf.setImage(with: imageURL)
cell.contentView.layer.cornerRadius = 2.0
cell.layer.shadowColor = UIColor.black.cgColor
cell.layer.shadowOpacity = 0.5
return cell
}
private func fetchCoinsData(completionHandler: @escaping (Result<[Coin], Error>) -> Void) {
let url = "https://api.coinpaprika.com/v1/coins"
AF.request(url, method: .get)
.responseData(completionHandler: { response in
switch response.result {
case let .success(data):
do {
let decoder = JSONDecoder()
let result = try decoder.decode([Coin].self, from: data)
completionHandler(.success(result))
} catch {
completionHandler(.failure(error))
}
case let .failure(error):
completionHandler(.failure(error))
}
})
}
override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let storyboard = UIStoryboard(name: "Main", bundle: Bundle.main)
guard let detailViewController = storyboard.instantiateViewController(identifier: "CoinDetailViewController") as? CoinDetailViewController else { return }
detailViewController.coinId = self.coins[indexPath.item].id
detailViewController.title = self.coins[indexPath.item].name
self.show(detailViewController, sender: nil)
}
}
extension CoinsViewController: UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let width = collectionView.frame.width
let cellWidth = (width - 4 * cellMargin) / 3
return CGSize(width: cellWidth, height: cellWidth)
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
return 0
}
}
API 호출을 조금 간결하게 만들어주는 Alamofire Library를 사용하였으며 이미지 셋에는 Kingfisher(킹피셔)를 사용했다.
코인 관련 구조체
struct Coin: Codable {
let id: String
let name: String
let symbol: String
let rank: Int
}
struct CoinDetail: Codable {
let id: String
let name: String
let links: [Link]
let description: String
enum CodingKeys: String, CodingKey {
case id
case name
case description
case links = "links_extended"
}
}
API는 https://api.coinpaprika.com/v1/coins 에서 호출하며, detail은 url 뒤에 /코인id값을 넣는 식이다. (/btc-bitcoin 같은)
코인 상세 페이지
about 코인명의 타이틀을 가지며, description을 준다. description은 UITextView로 height 100으로 고정시켰다.
바로 밑에는 관련 링크들인데 눌러보진 않았다(....)
링크 버튼을 누르면 연결된 페이지로 브라우저 연결 되는 식이다.
Author And Source
이 문제에 관하여(swift로 코인 앱 만들기 Part1. Coins), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@kmnkit/swift로-코인-앱-만들기-Part1.-Coins저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)