[swift] 왕기초적인 API 받아오기 2 (JSON Parsing)
지난 번에 요청한 JSON데이터 기억나시나요?
{
"coord": {
"lon": 126.9778,
"lat": 37.5683
},
"weather": [
{
"id": 800,
"main": "Clear",
"description": "clear sky",
"icon": "01d"
}
],
"base": "stations",
"main": {
"temp": 265.08,
"feels_like": 261.52,
"temp_min": 264.38,
"temp_max": 266.84,
"pressure": 1028,
"humidity": 27,
"sea_level": 1028,
"grnd_level": 1021
},
"visibility": 10000,
"wind": {
"speed": 1.86,
"deg": 294,
"gust": 3.83
},
"clouds": {
"all": 0
},
"dt": 1642122122,
"sys": {
"type": 1,
"id": 5509,
"country": "KR",
"sunrise": 1642113967,
"sunset": 1642149322
},
"timezone": 32400,
"id": 1835848,
"name": "Seoul",
"cod": 200
}
이 데이터를 바로 쓸 순 없겠져!!
내가 필요한 놈들만 쏙쏙 뽑아서 재구성해야 합니당
이번 시간에는 요청한 데이터를 내가 원하는 데이터로 바꿔볼 거에요!!
우선 프로젝트를 하나 만들구요.
가장 먼저는 각 레이블들의 레이아웃을 잡아줄게요!
저는 temp, feels_like, id, main만 나타내고 싶으니까, 4개의 레이블만 잡아줄게요.
이 부분은 간단하므로 더보기로 보시면 돼요!
class ViewController: UIViewController {
let tempLbl = UILabel()
let feelsLikeLbl = UILabel()
let idLbl = UILabel()
let mainLbl = UILabel()
override func viewDidLoad() {
super.viewDidLoad()
configureUI()
getWeather()
}
}
//MARK: -UI
extension ViewController {
final private func configureUI() {
setAttributes()
setConstraints()
}
final private func setAttributes() {
tempLbl.text = "temp"
feelsLikeLbl.text = "feels_Like"
idLbl.text = "id"
mainLbl.text = "main"
}
final private func setConstraints() {
[tempLbl, feelsLikeLbl, idLbl, mainLbl].forEach {
view.addSubview($0)
$0.translatesAutoresizingMaskIntoConstraints = false
}
NSLayoutConstraint.activate([
tempLbl.centerXAnchor.constraint(equalTo: view.safeAreaLayoutGuide.centerXAnchor),
tempLbl.centerYAnchor.constraint(equalTo: view.safeAreaLayoutGuide.centerYAnchor),
feelsLikeLbl.topAnchor.constraint(equalTo: tempLbl.bottomAnchor, constant: 15),
feelsLikeLbl.centerXAnchor.constraint(equalTo: view.safeAreaLayoutGuide.centerXAnchor),
idLbl.topAnchor.constraint(equalTo: feelsLikeLbl.bottomAnchor, constant: 15),
idLbl.centerXAnchor.constraint(equalTo: view.safeAreaLayoutGuide.centerXAnchor),
mainLbl.topAnchor.constraint(equalTo: idLbl.bottomAnchor, constant: 15),
mainLbl.centerXAnchor.constraint(equalTo: view.safeAreaLayoutGuide.centerXAnchor),
])
}
}
그리고 command N을 눌러 swift 파일을 하나 추가해줍니다!
이름은 WeatherData.swift로 해줄게요롱이.
그리고 WeatherData라는 구조체를 하나 만들어줍니다.
import Foundation
struct WeatherData: Codable {
}
그리고 Decodable이라는 프로토콜을 채택해주는데요.
Decodable을 옵션키를 누른채로 보면 외부 표현(아마도 JSON데이터?)를 해독하는 프로토콜이라고 하네요.
받아온 JSON data를 parsing하기 위해서는 이 프로토콜을 채택해야만 해요.
받아온 데이터를 보면 main 안에 있는 temp, feels_like / weather 안에 있는 id, main을 사용할 거에요.
"main": {
"temp": 1.1,
"feels_like": -0.56,
"temp_min": -0.77,
"temp_max": 1.78,
"pressure": 1021,
"humidity": 52
}
우선 main부터 볼게요. main의 값인 temp와 feels_like를 이용하기 위해서는 Weather 구조체 안에 또 Main이라는 구조체를 만들어 줍니다. 그리고 main 상수 선언하고 이 Main타입으로 만들어줘요.
+ Main 구조체 또한 Decodable 프로토콜을 채택해야 해요!!
struct WeatherData: Decodable {
let main: Main
struct Main: Decodable {
let temp, feelsLike, tempMin, tempMax: Double
let pressure, humidity: Int
}
}
이렇게 하면 main.temp를 통해 temp, feels_like 등과 같이 main의 속한 값들을 모두 사용할 수 있겠져?
근데!! 여기서 혹시 이상한 거 느껴지시나요? JSON 데이터에서는 feels_like였던 값이 여기에는 feelsLike로 바뀌어 있거든여!! 왓더!!
바로 CodingKey를 사용했기 때문인데여! swift에서는 'feels_like'보다는 'feelLike'가 익숙하잖아요? 이렇게 바꿀 수 있게 도와주는 것이 바로 CodingKey입니다!
CodingKey는 프로토콜이구요. 열거형으로 선언합니다.
사용하는 방법은 간단해여. 각 케이스에 내가 원하는 값을 원시값으로 설정해주면 됩니다요.
그러면 이제부터 feels_like를 우리가 익숙한 feelsLike로 사용할 수 있어여 ㅎㅎㅎ
실수할 일이 줄어들겠져?
struct WeatherData: Decodable {
let main: Main
struct Main: Decodable {
let temp, feelsLike, tempMin, tempMax: Double
let pressure, humidity: Int
//CodingKey
enum CodingKeys: String, CodingKey {
case temp
case feelsLike = "feels_like"
case tempMin = "temp_min"
case tempMax = "temp_max"
case pressure, humidity
}
}
}
이제 weather 상수를 만들어볼게욧
weather같은 형태가 실수하기 쉬운 형태라고 해요.
"weather": [
{
"id": 615,
"main": "Snow",
"description": "light rain and snow",
"icon": "13n"
}
]
아래 main과의 차이가 느껴지시나여? (저는 못 느꼈음 ㅎㅎ)
"main": {
"temp": 1.1,
"feels_like": -0.56,
"temp_min": -0.77,
"temp_max": 1.78,
"pressure": 1021,
"humidity": 52
}
weather는 [ ]에 한 번 더 감싸져있져?
main의 형태 -> [main: 값]
weather의 형태 -> [weather: [키:값]]
그렇기 때문에 상수 weather는 구조체 Weather타입이 아닌, [Weather] 타입이에요.
struct WeatherData: Codable {
let main: Main
let weather: [Weather]
struct Main: Codable {
let temp, feelsLike, tempMin, tempMax: Double
let pressure, humidity: Int
enum CodingKeys: String, CodingKey {
case temp
case feelsLike = "feels_like"
case tempMin = "temp_min"
case tempMax = "temp_max"
case pressure, humidity
}
}
struct Weather: Codable {
let id: Int
let main, weatherDescription, icon: String
enum CodingKeys: String, CodingKey {
case id, main
case weatherDescription = "description"
case icon
}
}
}
그리고 Weather 구조체에서도 CodingKey 프로토콜을 채택해줄게요.
처음에는 JSON 형태만 봐도 머리가 아팠는데, 이렇게 다시 구조체로 만들어보니 알거 같기도 하고?
그래도 역시나 잘못된 것이 있다면 알려주십셔 슨배님덜!