์ ๊ฐ ์์ ์ ์งํํ๋ ํ์๋ํ๊ต iOS ์ฑ์์, ๋ฉ๋ด ํ๋ฉด ๊ทธ๋ฆด ๋ URLSession์ ํตํด ๋ค์๊ณผ ๊ฐ์ JSON์ Parsing ํด์ผํฉ๋๋ค.
Swift4๋ถํฐ Codable Protocol์ด ๋์ ๋ผ์, JSON์ ๊ต์ฅํ ํธ๋ฆฌํ๊ฒ ์ฒ๋ฆฌํ ์ ์์ต๋๋ค.
์ฐ์ ์ ๊ฐ ์๋ฒ์ ํต์ ํ JSON ๊ท๊ฒฉ์ ๋ค์์ฒ๋ผ ๋ณต์กํ๊ฒ ๋์ด ์์ด์.
{
"result": {
"totalCount": 9,
"list": [
{
"ACT_URL": null,
"HOCHUL_GB": "L",
"ICON_NM": "ic_hanyang_sogae_l",
"MENU_NM": "ํ์์๊ฐ",
"MENU_SEQ": 1,
"MENU_ID": "911",
"MENU_ID2": "M319378"
},
{
"MENU_SEQ": 2,
"MENU_ID2": "M319362",
"ACT_URL": null,
"HOCHUL_GB": "L",
"ICON_NM": "ic_seoul_campus_l",
"MENU_ID": "912",
"MENU_NM": "์์ธ์บ ํผ์ค"
},
{
"MENU_ID2": "M319363",
"MENU_ID": "913",
"MENU_SEQ": 3,
"ICON_NM": "ic_erica_campus_l",
"HOCHUL_GB": "L",
"ACT_URL": null,
"MENU_NM": "ERICA์บ ํผ์ค"
},
{
"ACT_URL": "https://go.hanyang.ac.kr/new/mobile/main.html",
"MENU_ID2": null,
"MENU_SEQ": 4,
"ICON_NM": "ic_iphak_anne_l",
"HOCHUL_GB": "U",
"MENU_ID": "914",
"MENU_NM": "์
ํ์๋ด"
},
{
"MENU_SEQ": 5,
"ICON_NM": "ic_brain_hanyang_l",
"ACT_URL": null,
"MENU_ID2": "M008388",
"MENU_NM": "๋ธ๋ ์ธํ์",
"HOCHUL_GB": "L",
"MENU_ID": "915"
},
{
"MENU_NM": "๋ฐ์ ๊ธฐ๊ธ",
"MENU_SEQ": 6,
"MENU_ID": "916",
"MENU_ID2": "M008301",
"ACT_URL": null,
"ICON_NM": "ic_baljeon_gigeum_l",
"HOCHUL_GB": "L"
},
{
"HOCHUL_GB": "U",
"MENU_SEQ": 7,
"MENU_ID": "917",
"ICON_NM": "ic_parking_l",
"MENU_ID2": null,
"ACT_URL": "https://parking.hanyang.ac.kr/",
"MENU_NM": "์ฃผ์ฐจ๊ด๋ฆฌ"
},
{
"ACT_URL": "https://portal.hanyang.ac.kr/applink/lib.html",
"MENU_ID2": null,
"MENU_SEQ": 8,
"MENU_ID": "918",
"HOCHUL_GB": "A",
"ICON_NM": "ic_doseogwan_l",
"MENU_NM": "๋์๊ด"
},
{
"HOCHUL_GB": "U",
"MENU_ID": "919",
"ICON_NM": "ic_haksik_l",
"MENU_ID2": null,
"MENU_NM": "ํ๊ต์๋จ",
"MENU_SEQ": 9,
"ACT_URL": "https://www.hanyang.ac.kr/web/www/re1"
}
]
},
"nowDate": {
"dd": "15",
"mm": "04",
"yoil": "5",
"yyyy": "2021"
},
"resultMessage": {
"service": "/COMM/A202100004",
"code": 200,
"msg": ""
}
}
์ฐ์ ๊ฐ์ฅ ์๋จ์ ํค ๊ฐ์ด "result", "resultMessage", "nowDate"
์ด ์ธ๊ฐ์ง๊ฐ ์๊ธฐ ๋๋ฌธ์ ์ด๋ฅผ ํฌํจํ๋ Root๋ฅผ ๋ง๋ค์ด์ฃผ๊ณ , ๊ทธ ์๋ ๋ ์๋ค์ ํ๋์ฉ ์ถ๊ฐํฉ๋๋ค.
๊ทธ๋ฌ๋ฉด ๋ค์๊ณผ ๊ฐ์ด 4๊ฐ์ง ๋ชจ๋ธ์ด ํ์ํด์.
struct Root<T: Codable>: Codable {
var result: Result<T>?
var nowDate: [String:String]?
var resultMessage: ResultMessage?
}
struct Result<T: Codable>: Codable{
var list: [T]?
var totalCount: Int?
}
struct ResultMessage: Codable {
let code:Int?
let msg:String?
let service: String?
}
struct MenuItem: Codable {
let MENU_NM: String?
let ICON_NM: String?
let ACT_URL: String?
let HOCHUL_GB: String?
let MENU_ID: String?
let MENU_ID2: String?
let MENU_SEQ: Int?
let DEL_POSSIBLE_YN: String?
}
์ด ๊ฒฝ์ฐ์๋ Generic์ ์ฌ์ฉํ๋ฉด, ํธํ๊ฒ ํ์ฑํ ์ ์์ต๋๋ค.
์ด๋ ๊ฒ ๊ตฌ์กฐ์ฒด๋ฅผ ๋ง๋ค์์ผ๋ฉด, ํ์ฑํ๋ ๋ฐฉ๋ฒ์
URLSession์ผ๋ก request๋ฅผ ๋ ๋ฆฌ๊ณ , JSONDecoder๋ฅผ ์ด์ฉํ๋ฉด ๋ฉ๋๋ค.
API ์์ฒญ์ ์ฃผ๋ก App Lifecycle์์ viewWillAppear์์ ์ฃผ๋ก ํฉ๋๋ค.
override func viewWillAppear(_ animated: Bool) {
if loadingIndicator.isAnimating {
guard let url = URL(string: "๋น๊ณต๊ฐURL") else { return }
var req = URLRequest(url: url)
req.httpMethod = "GET"
req.setValue("application/x-www-form-urlencoded; charset=utf-8", forHTTPHeaderField: "Content-Type")
let task = URLSession.shared.dataTask(with: req) { data, response, error in
let root = try! JSONDecoder().decode(Root<MenuItem>.self, from: data!)
self.menuItems = root.result!.list!
}
task.resume()
}
}
๋ก๋ฉ indicator๊ฐ ๋๊ณ ์์ผ๋ฉด, Request๋ฅผ ๋ ๋ฆฝ๋๋ค.
๊ทธ๋ฆฌ๊ณ ์ฑ๊ณต์ ์ผ๋ก ํ์ฑ์ ํ๋ฉด self.menuItems์ list๋ฅผ ์ค์ ํด์ค๋๋ค.
URLSession์ ๊ธฐ๋ณธ์ ์ผ๋ก ๋ฐฑ๊ทธ๋ผ์ด๋ ํ์์ ์คํ ๋๊ธฐ ๋๋ฌธ์ UI๋ฅผ ์์ ํ๋ ๋ถ๋ถ์ ๋ฉ์ธ ์ฐ๋ ๋์์ ํด์ค์ผ ํฉ๋๋ค.
๋ค์๊ณผ ๊ฐ์ด ๊ฐ์ด ์ค์ ๋๋ฉด, CollectionView๋ฅผ Reloadํด์ฃผ๊ณ , Loading Indicator๋ฅผ ๋ฉ์ถ๋ฉด ๋ฉ๋๋ค.
var menuItems:[MenuItem] = [] {
didSet {
DispatchQueue.main.async {
self.menuCollectionView.reloadData()
self.loadingIndicator.stopAnimating()
}
}
}
์ดํ ์ฌ๋ฐ๋ฅด๊ฒ ํ๋ฉด์ด ๊ฐฑ์ ๋จ์ ํ์ธํ ์ ์์ต๋๋ค ใ ใ
'iOS ๐ฅ > Swift' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
Swift์์ Abstract Class ๋ง๋ค๊ธฐ (0) | 2023.06.06 |
---|---|
Swift ์๋ฌ ์ฒ๋ฆฌ(Error Handling) (0) | 2021.06.25 |
Swift ํด๋์ค ์์๊ณผ ์ด๊ธฐํ (0) | 2021.06.25 |
Swift Date์ String ๊ฐ์ ๋ณํ (0) | 2021.04.07 |
Swift Enum๊ณผ Optional (0) | 2021.02.09 |