이전 글에서 Codable에 대해 공부를 했었는데요. 이번글에서는 Codable을 쓰면 좋은 점을 URLRequest +URLSession vs Alamofire 을 비교하면서 공부를 해볼까 합니다. 지난 글의 연장선이라고 할 수 있습니다.
저번 글과 마찬가지로 https://www.youtube.com/watch?v=w7xJrAYQoHE 이 유튜브에서 나오는 REST API url을 사용할 것입니다.
// 위에서 언급했던 url 에서 정의된 JSON형식의 데이터
{
"results":{
"sunrise":"2022-09-01T02:45:56+00:00",
"sunset":"2022-09-01T16:15:33+00:00",
"solar_noon":"2022-09-01T09:30:45+00:00",
"day_length":48577,
"civil_twilight_begin":"2022-09-01T03:23:30+00:00",
"civil_twilight_end":"2022-09-01T15:37:59+00:00",
"nautical_twilight_begin":"2022-09-01T04:08:49+00:00",
"nautical_twilight_end":"2022-09-01T14:52:41+00:00",
"astronomical_twilight_begin":"2022-09-01T04:54:38+00:00",
"astronomical_twilight_end":"2022-09-01T14:06:51+00:00"
},
"status":"OK"
}
데이터의 형식은 {"result" : {딕셔너리}, "status" : "OK"} 형식으로 root Object as Object타입입니다.
Codable에 맞게 위 데이터를 전부 받아오기 위한 설계를 목표로 가정할 것입니다.
1. 데이터를 JSON형식으로 파싱할 struct 정의하기
Codable 프로토콜 규칙을 준수하여 구조체를 정의하면
struct APIResponse: Codable{
let results : WeatherResponse
let status : String
}
struct WeatherResponse: Codable{
var sunrise: String
let sunset: String
let solar_noon: String
let day_length: Int
let civil_twilight_begin: String
let civil_twilight_end: String
let nautical_twilight_begin: String
let nautical_twilight_end: String
let astronomical_twilight_begin: String
let astronomical_twilight_end: String
}
이때 원하는 키에 해당하는 프로토콜만 선언해도 됩니다.
2-1. URLRequset + URLSession 으로 Codable 인스턴스 얻기
1. URLResponse로 HTTP 헤더 정의
2. URLSession으로 데이터 파싱
3. dataTask으로 성공적으로 요청한 이후에 받은 데이터를 JSONDecoder().decode(_:from:) 를 통해 Codable 인스턴스 얻기!
func getDataWithURLSession(){
// 1. set URLRequest Line-Header-body
guard let url = URL(string: urlStr) else {
return
}
guard var request = try? URLRequest(url: url) else {
print("Can't get URLRequest instance")
return
}
request.httpMethod = "GET"
request.addValue("application/json; charset=utf-8", forHTTPHeaderField: "Content-Type")
// 2. url 객체로 구현된 Request를 통한 dataTask HTTP통신
let task = URLSession.shared.dataTask(with: request) { data, response, error in
guard let _data = data, error == nil else {
return
}
// JSONDecoder를 통해 우리가 정한 커스텀 자료 구조로 디코딩
guard let res = try? JSONDecoder().decode(APIResponse.self, from: _data) else {
print("Can't deocde")
return
}
print(res)
}
task.resume()
}
이후의 res인스턴스는 APIResponse 인스턴스 사용하듯 사용하면 됩니다.(개꿀..)
2-2. Alamofire responseDecodable(of:)로 Codable 인스턴스 얻기
이방법은 위 방법보다 더 간단합니다.
func getDataWithAFResponseDecodable(){
//RESIful API에 데이터 요청
let call = AF.request(urlStr, method: .get, encoding: JSONEncoding.default)
//Decode
call.responseDecodable(of: APIResponse.self){ response in
guard response.error == nil else{
print("에러")
return
}
switch response.result{
case .success(_):
guard let _data = response.value else {
print("Failed binding response.value")
return
}
print(_data.results)
break
case .failure(_):
break
}
}
}
3. Codable을 사용하지 않은 경우 URLRequest + URLSession으로 JSON데이터 파싱하기
1. 일반 구조체 생성
2. 바이트 데이터를 JSONSerialization으로 JSON타입으로 변환
3. 변환된 Object의 키를 통해 value를 프로퍼티에 저장
4. 1에서 생성한 구조체에 대입
func getDataWithURLSessionDefault() {
// 1. set URLRequest Line-Header-body
guard let url = URL(string: urlStr) else {
return
}
guard var request = try? URLRequest(url: url) else {
print("Can't get URLRequest instance")
return
}
request.httpMethod = "GET"
request.addValue("application/json; charset=utf-8", forHTTPHeaderField: "Content-Type")
// 2. url 객체로 구현된 Request를 통한 dataTask HTTP통신
let task = URLSession.shared.dataTask(with: request) { data, response, error in
guard let _data = data, error == nil else {
return
}
guard let json = try? JSONSerialization.jsonObject(with: _data, options: []) as? NSDictionary else{
print("can't parse as NSDictionary")
return
}
let status = json["status"] as? String ?? ""
guard let results = json["results"] as? NSDictionary else {
print("results key value is nil")
return
}
let sunrise = results["sunrise"] as? String ?? ""
let sunset = results["sunset"] as? String ?? ""
let solar_noon = results["solar_noon"] as? String ?? ""
let day_length = results["day_length"] as? Int ?? -1
let civil_twilight_begin = results["civil_twilight_begin"] as? String ?? ""
let civil_twilight_end = results["civil_twilight_end"] as? String ?? ""
let nautical_twilight_begin = results["nautical_twilight_begin"] as? String ?? ""
let nautical_twilight_end = results["nautical_twilight_end"] as? String ?? ""
let astronomical_twilight_begin = results["astronomical_twilight_begin"] as? String ?? ""
let astronomical_twilight_end = results["astronomical_twilight_end"] as? String ?? ""
let _results = WeatherResponseDefault(sunrise: sunrise, sunset: sunset, solar_noon: solar_noon,
day_length: day_length, civil_twilight_begin: civil_twilight_begin,
civil_twilight_end: civil_twilight_end, nautical_twilight_begin: nautical_twilight_begin,
nautical_twilight_end: nautical_twilight_end, astronomical_twilight_begin: astronomical_twilight_begin,
astronomical_twilight_end: astronomical_twilight_end)
let weatherInfo = APIResponseDefault(results: _results, status: status)
}
task.resume()
}
읔.. 앞으로 저는 Codable만 사용할 것 같습니다.
'iOS > DataParsing' 카테고리의 다른 글
[iOS] FireStore Database document에 값을 Codable타입으로 디코딩, 인코딩으로 저장, 꺼내오기!! (0) | 2022.10.30 |
---|---|
[iOS] Codable로 String타입의 JSON데이터-> Data타입으로 Decode. | String -> UIImage decode? #5 (2) | 2022.09.29 |
[iOS] Codable 개념 뿌수기!! #3 (0) | 2022.09.06 |
[iOS] JSON형식의 데이터 파싱 뿌수기!! with Alamofire #2 (0) | 2022.09.06 |