iOS/패스트캠퍼스(앱제작)

코로나 현황판 앱

soultreemk 2022. 5. 8. 17:43

<주요기능>

1.  api를 호출, 시도별 코로나 신규 확진자 수를 파이차트로 표시

2. 차트의 도시항목 클릭 -> 상세 현황 보기

- 굿바이 코로나 19 API

- Alamofire : http통신방법

- Cocoapods:  외부 라이브러리를 관리하기 쉽게 도와주는 의존성관리 도구

 


 

  • Alamofire란
    - 스위프트 기반의 HTTP네트워킹 라이브러리
    - 네트워킹을 위한 다양한 메소드, json파싱 제공 -> 작업 단순화
    특징)
    1) request, response 메소드 제공
    2) json형태의 파라미터 인코딩 지원
    3) 파일 데이터스트림 등 업로드 기능 제공

 

  • URLSession 대신 Alamofire를 사용하는 이유
    - 코드의 간소화, 가독성 측면에서 유리. 여러 기능을 직접 구축하지 않아도 쉽게 사용 가능

URLSession을 이용하면 URL생성, statusCode  처리(유효성검사), error처리 등을 직접 작성해야 함

Alamofire는 validate메소드만 호출하면 됨

 

  • Alamofire Request

  • Alamofire Response

 


 

1. json데이터를 응답받을 구조체 선언

더보기
//  CityCovidOverview.swift

import Foundation

struct CityCovidOverview: Codable {
    let korea: CovidOverview
    let seoul: CovidOverview
    let busan: CovidOverview
    let daegu: CovidOverview
    let incheon: CovidOverview
    let gwangju: CovidOverview
    let daejeon: CovidOverview
    let ulsan: CovidOverview
    let sejong: CovidOverview
    let gyeonggi: CovidOverview
    let gangwon: CovidOverview
    let chungbuk: CovidOverview
    let chungnam: CovidOverview
    let jeonbuk: CovidOverview
    let jeonnam: CovidOverview
    let gyeonbuk: CovidOverview
    let gyeonnam: CovidOverview
    let jeju: CovidOverview
}

struct CovidOverview: Codable {
    let countryName: String
    let newCase: String
    let totalCase: String
    let recovered: String
    let death: String
    let percentage: String
    let newCcase: String
    let newFcase: String
}

 

2. Alamofier로 API호출

- @ecsaping closure : Http 비동기 통신때 사용

https://jusung.github.io/Escaping-Closure/

더보기
//
//  ViewController.swift
//  COVID19
//
//  Created by YANG on 2022/05/08.
//

import UIKit
import Alamofire
import Charts

class ViewController: UIViewController {
    @IBOutlet weak var totalCaseLabel: UILabel!
    @IBOutlet weak var newCaseLabel: UILabel!
    @IBOutlet weak var pieChartView: PieChartView!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        self.fetchCovidOverview(completionHandler: { [weak self] result in
            guard let self = self else { return }
            switch result {
            case let .success(result):
                debugPrint("success \(result)")
            case let .failure(error):
                debugPrint("error \(error)")
            }
        })
    }
    // 서버에서 json데이터를 응답받거나 요청에 실패했을때 클로저함수 호출 -> 해당 클로저를 정의한 곳에 응답받은 데이터를 전달
    // escaping클로져 개념
    func fetchCovidOverview(completionHandler: @escaping (Result<CityCovidOverview, Error>) -> Void ) {
        let url = "https://api.corona-19.kr/korea/country/new/"
        let param = [
            "serviceKey" : "발급받은api키"
        ]
        
        AF.request(url, method: .get, parameters: param)
        // 응답데이터를 받을수 있는 메소드 체이닝: 응답데이터가 closure파라미터(response)로 전달됨
            .responseData(completionHandler: { response in
            switch response.result {
            // 응답받은 json데이터를 정의한 구조체로 매핑
            case let .success(data):
                do {
                    let decoder = JSONDecoder()
                    let result = try decoder.decode(CityCovidOverview.self, from: data)
                    completionHandler(.success(result))
                } catch {
                    completionHandler(.failure(error))
                }
                
            case let .failure(error):
                completionHandler(.failure(error))
            }
            
        })
        
    }
}

 

3. 파이차트에 결과 보여주기

더보기
class ViewController: UIViewController {
    @IBOutlet weak var totalCaseLabel: UILabel!
    @IBOutlet weak var newCaseLabel: UILabel!
    @IBOutlet weak var pieChartView: PieChartView!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        self.fetchCovidOverview(completionHandler: { [weak self] result in
            guard let self = self else { return }
            switch result {
            case let .success(result):
                self.configureStackView(koreaCovidOverview: result.korea)
				// 파이차트에 표시하려면 list형으로 변환해야함
                let covidOverviewList = self.makeCovidOverviewList(cityCovidOverview: result)
                self.configureChartView(covidOverviewList: covidOverviewList)
            case let .failure(error):
                debugPrint("error \(error)")
            }
        })
    }
    
    func configureStackView(koreaCovidOverview: CovidOverview) {
        self.totalCaseLabel.text = "\(koreaCovidOverview.totalCase)명"
        self.newCaseLabel.text = "\(koreaCovidOverview.totalCase)명"
    }
    
    // json데이터가 리스트로 반환되어야 chartView에 표시 가능
    func makeCovidOverviewList(cityCovidOverview: CityCovidOverview) -> [CovidOverview] {
        return [
            cityCovidOverview.seoul,
            cityCovidOverview.busan,
            cityCovidOverview.daegu,
            cityCovidOverview.gwangju,
            cityCovidOverview.daejeon,
            cityCovidOverview.gyeonggi
        ]
        
    }
    
    func configureChartView(covidOverviewList: [CityCovidOverview]) {
        self.pieChartView.delegate = self
        // 반복 코드 생략
    }

 

4. 지역이름 클릭 시 상세보기 화면으로 이동
- chartView delegate 구현

더보기
extension ViewController: ChartViewDelegate {
    func chartValueSelected(_ chartView: ChartViewBase, entry: ChartDataEntry, highlight: Highlight) {
        guard let covidDetailViewController = self.storyboard?.instantiateViewController(withIdentifier: "CovidDetailViewController") else { return }
        guard let covidOverview = entry.data as? CovidOverview else { return }
        covidDetailViewController.covidOverview = covidOverview
        self.navigationController?.pushViewController(covidDetailViewController, animated: true)
    }
}

 

5.  json 로딩 시 progress bar 표시

더보기
class ViewController: UIViewController {
    @IBOutlet weak var totalCaseLabel: UILabel!
    @IBOutlet weak var newCaseLabel: UILabel!
    @IBOutlet weak var pieChartView: PieChartView!
    @IBOutlet weak var indicationView: UIActivityIndicatorView!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // 서버에서 응답오기 전
        self.indicationView.startAnimating()
        
        self.fetchCovidOverview(completionHandler: { [weak self] result in
            guard let self = self else { return }
            // 서버에서 응답 온 후
            self.indicationView.stopAnimating()
            self.indicationView.isHidden = true
            self.pieChartView.isHidden = false
            
            switch result {
            case let .success(result):
                self.configureStackView(koreaCovidOverview: result.korea)
                let covidOverviewList = self.makeCovidOverviewList(cityCovidOverview: result)
                self.configureChartView(covidOverviewList: covidOverviewList)
            case let .failure(error):
                debugPrint("error \(error)")
            }
        })
    }