-
์๋๋ณ ์ ๊ท ํ์ง์ ์๊ฐ ํ์ด ์ฐจํธ๋ก ํ์ ๋์ด์ผ ํฉ๋๋ค
-
๋์ ํญ๋ชฉ์ ์ ํํ๋ฉด ์์ธ ํํฉ์ ๋ณผ ์ ์๋ ํ๋ฉด์ผ๋ก ์ด๋๋์ด์ผ ํฉ๋๋ค.
// in 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 gyeongbuk: CovidOverview
let gyeongnam: 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
}
// in CovidTime.swift
import Foundation
struct CovidTime: Codable {
let updateTime: String
}
Corona-19-API - https://github.com/dhlife09/Corona-19-API
- Alamofire ๋ Swift ๊ธฐ๋ฐ์ HTTP ๋คํธ์ํน ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ ๋๋ค. URLSession ์ ๊ธฐ๋ฐ์ผ๋ก ํ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ก์, ๋คํธ์ํน ์์ ์ ๋จ์ํ ํ๊ณ ๋คํธ์ํน์ ์ํ ๋ค์ํ method, json parsing ๋ฑ์ ์ ๊ณต ํฉ๋๋ค.
- ์ฐ๊ฒฐ ๊ฐ๋ฅํ request, response method ๋ฅผ ์ ๊ณตํ๋ฉฐ, URL json parameter encoding ์ ์ง์ ํฉ๋๋ค. ํ์ผ ๋ฐ์ดํฐ ์คํธ๋ฆฌ๋ฐ, multi part form date ๋ฑ upload ๊ธฐ๋ฅ์ ์ ๊ณตํ๋ฉฐ, HTTP response ๊ฒ์ฆ๊ณผ ๊ด๋ฒ์ํ Unit Test, ํตํฉ Test ๋ฑ์ ์ง์ํฉ๋๋ค
-
func ์์ escape ์ ์ธ์ ํจ์์ scope ๋ฅผ ๋ฒ์ด ๋์๋ ๋ณ์๊ฐ ์ฐธ์กฐ ๋ ์ ์๊ฒ ํ๋ ํด๋ก์ ธ ์. ์ฆ, ํจ์์ ์ธ์๋ก closure ๊ฐ ์ ๋ฌ๋์ง๋ง, ๋ฐํ๋ ํ์๋ ์คํ๋๋ ๊ฒ์ ์๋ฏธํฉ๋๋ค.
-
escaping closure ๋ฅผ ์ฌ์ฉํ๋ ๋ํ์ ์ธ ๊ฒฝ์ฐ๋ ๋น๋๊ธฐ ์์ ์ ํ๋ ๊ฒฝ์ฐ completionHandler ๋ก์ escaping closure ๋ฅผ ๋ง์ด ์ฌ์ฉํฉ๋๋ค. ๋ณดํต ๋คํธ์ํน ํต์ ์ ๋น๋๊ธฐ ์์ ์ผ๋ก ์ฒ๋ฆฌ ๋๋๋ฐ,
.responseData
์ ์ ์๋completionHandler closure
๋ fetch data ๊ฐ ๋ฐํ ๋ ํ์, ํธ์ถ์ด ๋ฉ๋๋ค. ์๋ํ๋ฉด, ์๋ฒ์์ ๋ฐ์ดํฐ๋ฅผ ์ธ์ ์๋ต ํด์ค์ง ๋ชจ๋ฅด๊ณ , ์๋ต์๊ฐ์ด ๋ก๋ฉ ๋๊ธฐ ๋๋ฌธ์ server ์์ ๋น๋๊ธฐ๋ก ์๋ต ๋ฐ๊ธฐ ์ ์ ์ฆ, .responseData ์ ์ ๋ฌํ parameter ๊ฐ completionHandler๊ฐ ํธ์ถ๋๊ธฐ ์ ์ ํจ์๊ฐ ์ข ๋ฃ๋์ ์๋ฒ์ ์๋ต์ ๋ฐ์๋ ๋์ํ์ง ์๊ฒ ๋ฉ๋๋ค -
๊ทธ๋์, ๋น๋๊ธฐ ์์ ์ completionHandler ๋ก callback ์ ์์ผ์ค์ผ ํ๋ค๋ฉด, escaping closure ๋ฅผ ์ฌ์ฉํ์ฌ ํจ์๊ฐ return ๋ ํ์๋, ์คํ ์์ผ์ค์ผ ํฉ๋๋ค
// in viewDidLoad.swift
// fetch data SearchCovideOverview
func fetchCovidOverview(
// API ๋ฅผ ํตํด์ sever์์ json dat ๋ฅผ ๋ฐ๊ฑฐ๋, ์์ฒญ์ ์คํจ ํ์์๋ completionHandler ๋ฅผ ํธ์ถํด์ ํด๋น closure ๋ฅผ ์ ์ํ๋ ๊ณณ์ ์๋ต๋ฐ์ data๋ฅผ ์ ๋ฌ ํด์ผ ํฉ๋๋ค
// completionHandler ๋ฅผ @escaping closure ๊ฐ ๋๊ฒ ์ค์
completionHandler: @escaping (Result<CityCovidOverView, Error>) -> Void
) {
let url = "https://api.corona-19.kr/korea/country/new/"
let param = [
"serviceKey": "16KIXAdhg7tk93ivjzsHFCQ8oOLyNSUuE"
]
// Alamofire ๋ฅผ ํตํด์ API ํธ์ถ
AF.request(url, method: .get, parameters: param)
.responseData(completionHandler: { response in
switch response.result {
case let .success(data):
do {
let decoder = JSONDecoder()
let result = try decoder.decode(CityCovidOverView.self, from: data)
completionHandler(.success(result))
} catch { // error code ์ฒ๋ฆฌ
completionHandler(.failure(error))
}
case let .failure(error):
completionHandler(.failure(error))
}
})
}
-
Apple platform ์์ ๊ฐ๋ฐ์ ํ ๋, ์ธ๋ถ ๋ผ์ด๋ธ๋ฅผ ๊ด๋ฆฌํ๊ธฐ ์ฝ๋๋ก ๋์์ฃผ๋ ์์กด์ฑ ๊ด๋ฆฌ๋๊ตฌ ์ ๋๋ค
-
ํ๋ก์ ํธ์์ ํ์ํ ์ธ๋ถ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฝ๊ฒ ๊ด๋ฆฌํ๊ณ , ์ฌ์ฉํ ์ ์์ต๋๋ค.
Cocoapods official site - https://cocoapods.org/
$ sudo gem install cocoapods
- xcode ๋ก ์๋ก์ด project ๋ฅผ ์์ฑํ๋ฉด ๊ทธ ๊ฒฝ๋ก์ terminal ๋ก ๊ฐ์ Podfile ์์ฑ
pod init
- Podfile ์ ์์ ํ๊ฒ ๋๋ฉด ์ธ๋ถ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ๊ฐ์ ธ์ค๊ฑฐ๋, ์์ ํ ์ ์์ต๋๋ค.
-
ViewController ์ loading indicator ๋ฅผ ํ์ํ์ฌ, Covid API ๋ฅผ ํธ์ถ ํ์์ ๋, ์๋ฒ์์ ์๋ต์ด ์ค๊ธฐ ์ ์ด๋ผ๋ฉด ํ๋ฉด์ indicator ๊ฐ ํ์๋๊ฒ ๊ตฌํํ๊ธฐ
-
์๋ฒ์์ ์๋ต์ด ์จ๋ค๋ฉด, indicator ๋ฅผ ์จ๊ธฐ๊ณ label ๊ณผ pieChart ๊ฐ ํ์๋๊ฒ ๊ตฌํ ํ๊ธฐ
- storyboard ์์ Activity Indicator ์ถ๊ฐ ํ๋ค์์ ๊ธฐ์กด์ StackView์ label, pieChartView ์๋ hidden ์ ์ฒดํฌ ํด์ค์ ์ ์ ์จ๊น๋๋ค
// in ViewController.swift
override func viewDidLoad() {
super.viewDidLoad()
// app ์ด ์คํ๋๋ฉด indicator ์ animation ์์
self.indicatorView.startAnimating()
// ์ํ์ฐธ์กฐ๋ฅผ ๋ฐฉ์งํ๊ธฐ ์ํด์ [weak self] ๋ก capture list ๋ฅผ ์ ์ํด์ค
self.fetchCovidOverview(completionHandler: { [weak self] result in
guard let self = self else { return } // self ๊ฐ ์ผ์์ ์ผ๋ก strong ์ด ๋๊ฒ ํจ
// ์๋ต์ด ์ค๋ฉด completionHandler ๊ฐ ์๋๋๊ธฐ ๋๋ฌธ์ ์ด๋ indicatorView ์ animating ์ stop ์์ผ ์ฃผ๊ณ , hidden ์์ผ ์ฃผ๊ณ , ๋๋จธ์ง information data ๋ถ๋ถ์ด ๋ํ๋๊ฒ ํด์ค
self.indicatorView.stopAnimating()
self.indicatorView.isHidden = true
self.labelStackView.isHidden = false
self.readingDate.isHidden = false
self.pieChartView.isHidden = false
......
}
}
- GitHub ๋ ์ธ๋ถ๋ก public ํ๊ฒ project ๊ณต์ ์, apiKey ๋, passWord, authentication ๊ด๋ จ key ๊ฐ๋ค์ ์ธ๋ถ์ ๋ ธ์ถ ์ํค์ง ์๊ธฐ ์ํด์ code ์ key ๊ฐ์ ๋ฐ๋ก ์ ๋๊ฒ์ด ์๋๋ผ, plist (property list) ๋ฅผ ์์ฑํด์ค์ ๋ฐ๋ก ๊ด๋ฆฌ ํด์ผ ํฉ๋๋ค
- Key ๊ฐ์ผ๋ก
API_KEY
value ๊ฐ์ผ๋ก API key ๊ฐ์ ๋ฃ์ต๋๋ค
// in CovidApp++Bundle.swift
// "์ฑ์ด๋ฆ++Bundle.swift ํ์์ผ๋ก
import Foundation
// Bundle ๊ฐ์ผ๋ก ๋ณ์ key ๋ฅผ return
extension Bundle {
var apiKey: String {
guard let file = self.path(forResource: "CovidKey", ofType: "plist") else { return ""}
guard let resource = NSDictionary(contentsOfFile: file) else {return ""}
guard let key = resource["API_KEY"] as? String else { fatalError("Check API Key value")}
return key
}
}
๐ Bundle ์ extension ํด์ ์์ฑํ๋ ์ด์ ?
-
Bundle ์ด๋ ์คํ๊ฐ๋ฅํ ์ฝ๋์ ๊ทธ ์ฝ๋์ ์์์ ํฌํจํ๊ณ ์๋ ๋๋ ํ ๋ฆฌ ์ ๋๋ค.
-
Bundle ์์ apiKey ๊ฐ์ ๊ฐ์ ธ์ค๊ธฐ ์ํด
Bundle.main.apiKey
์์ผ๋ก ์ ๊ทผํด์ ์ฌ์ฉํฉ๋๋ค
// in viewController.swift
// fetch data SearchCovideOverview
func fetchCovidOverview(
// API ๋ฅผ ํตํด์ sever์์ json dat ๋ฅผ ๋ฐ๊ฑฐ๋, ์์ฒญ์ ์คํจ ํ์์๋ completionHandler ๋ฅผ ํธ์ถํด์ ํด๋น closure ๋ฅผ ์ ์ํ๋ ๊ณณ์ ์๋ต๋ฐ์ data๋ฅผ ์ ๋ฌ ํด์ผ ํฉ๋๋ค
// completionHandler ๋ฅผ @escaping closure ๊ฐ ๋๊ฒ ์ค์
completionHandler: @escaping (Result<CityCovidOverView, Error>) -> Void
) {
let apiKey = Bundle.main.apiKey
let url = "https://api.corona-19.kr/korea/country/new/"
let param = [
"serviceKey": apiKey
]
....
# Created by https://www.toptal.com/developers/gitignore/api/xcode,cocoapods
# Edit at https://www.toptal.com/developers/gitignore?templates=xcode,cocoapods
### CocoaPods ###
## CocoaPods GitIgnore Template
# CocoaPods - Only use to conserve bandwidth / Save time on Pushing
# - Also handy if you have a large number of dependant pods
# - AS PER https://guides.cocoapods.org/using/using-cocoapods.html NEVER IGNORE THE LOCK FILE
Pods/
### Xcode ###
# Xcode
#
# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
##APIKEY
CovidKey.plist
## User settings
xcuserdata
.....
- ์ถํ git clone project ์คํ์ local ํ๊ฒฝ์์ APIKEY ๊ฐ์ด ๋ณ๊ฒฝ๋๋๋ผ๋ git ์์ ์๋ ์ถ์ ๋์ง ์๊ณ gitHub ๋ฑ์ ์ ๋ก๋ ๋์ง ์๊ฒ ํ๊ธฐ์ ๋๋ค
# git update-index --skip-worktree ํ๋ก์ ํธ๋ช
/ํ์ผ๋ช
.plist
git update-index --skip-worktree 07_covid_app/covidKey.plist
- ๋ค์ ์์ ๋ณต๊ท๋
--no-skip
ํด์ฃผ๋ฉด ๋ฉ๋๋ค
git update-index --no-skip-worktree 07_covid_app/covidKey.plist
Describing check point in details in Jacob's DevLog - https://jacobko.info/ios/ios-08/
๐ถ ๐ท ๐ ๐ ๐
Jacob's DevLog - https://jacobko.info/uikit/ios-08/
๋๋ฅธํ ์ฝ๋ฉ - https://nareunhagae.tistory.com/44
codewithchrist - https://codewithchris.com/alamofire/
fastcampus - https://fastcampus.co.kr/dev_online_iosappfinal