본문 바로가기

iOS/DataParsing

[iOS] JSON형식의 데이터 파싱 뿌수기!! with Alamofire #2

이전에 작성한 RESTful API 파싱 방법은 URLRequest에 헤더를 정의하고 URLSession의 dataTask(with:)를 통해 결과 응답 처리 이후 .resume()로 HTTP 요청 메시지를 전송했었습니다.

 

Alamofire은 URLRequest와 URLSession을 더 쉽게 사용할 수 있는 오픈 라이브러리 입니다. HTTP 네트워킹을 위해 스위프트 기반으로 개발된 비동기 라이브러리이고,, 정말 편리합니다. Codable을 채택한 데이터 파싱은 코드 길이가 많이 줄어든다고 생각합니다.

 

Alamofire(5. ver) 특징

  • URLRequest + URLSession 객체를 Wrapping해 AF namesapce를 사용해 간결하게 사용할 수있게되었습니다.
  • 서버요청 간결!!
  • 서버 응답 컨텐츠 타입에 맞춰 사용할 수  있는 response 메서드가 다양합니다. (responseData, responseJSON, responseDecodable...)
  • resopnseJSON은 서버로부터 받은 결과값을 쉽게 JSON으로 파싱이 가능합니다.
  • responseDecodable 또한 JSONDecoder().decode(_:from:) 을 사용하지않고 바로 서버에서 받은 data를 decodable타입으로 변환 받을 수 있다느 장점이 있습니다.

Alamofire 사용 방법이다. 여기에 request 사용 enum들과 response를 사용할 수 있는 방법이 있습니다. 그중에서 난 요즘 response를 많이 사용하고 있는데,, Alamofire 사용 방법의 Response Handling 파트를 보면 상세하게 사용 방법이 나옵니다.

 

AF.reqeust(url주소!!).response{ resopnse in ... } 와 유사하게 사용을 할 수 있습니다.


 

URLRequest + URLSession과 Alamofire 코드 차이

https://www.youtube.com/watch?v=w7xJrAYQoHE

이 유튜브를 통해 Codable을 공부하고 있는데 이때 JSON형식의 RESTful API url이 있습니다. 이 URL을 통해 지금부터 데이터를 클라이언트로 받아오는데 URLRequest + URLSession과 Alamofire 코드 차이를 간단히 비교해 볼 것입니다.

 

1. 데이터를 JSON형식으로 파싱할 struct 정의하기

// 위에서 언급했던 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" }.  키 : value , 키 : value 인 딕셔너리 타입입니다.

top level의키로써 두개의 자료를 갖는 구조와, result키 value에 해당하는 key들을 또 자료로 하는 구조를 만들것입니닷..

 

Key에 해당하는 자료 구조의 struct를 만들면,

struct APIResponseDefault{
    var results : WeatherResponseDefault
    var status  : String
}
struct WeatherResponseDefault{
    var sunrise: String
    var sunset: String
    var solar_noon: String
    var day_length: Int
    var civil_twilight_begin: String
    var civil_twilight_end: String
    var nautical_twilight_begin: String
    var nautical_twilight_end: String
    var astronomical_twilight_begin: String
    var astronomical_twilight_end: String
}

이렇게 선언할 수 있습니다.

 

2-1. URLResponse + URLRequest로 데이터 파싱하기

1. URLRequest로 요청 메시지 보내기!! (Line, header, body) 속성 추가!!

func getData(){
	guard let url = URL(string: urlStr) else{
    	return
    }
    
    guard var request = try? URLRequest(url: url) else {
    	print("Can't get URLReqeust instance")
    	return
    }
    
    request.httpMethod = "GET"
    request.addValue("application/json; charset=utf-8", forHTTPHeaderField:"Content-Type") 
}

url 주소를 통한 URL인스턴스를 생성하고 URLRequest 인스턴스에 요청 헤더를 정의합니다.

 

2. request를 URLSession의 dataTask(with:).resume()으로 HTTP 통신을합니다.

func getData(){
	...
    //위에서부터 이어서
    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
    }
}

URLSession의 dataTask(with:)로 요청받은 데이터 옵셔널을 바인딩 해제 후 JSON직렬화를 합니다. 위에서 struct 정의할때 API 형식을 파악했지만 root object as object 형식이어서 NSDictionary를 사용해 캐스팅했습니다.

이후 json인스턴스가 nil이 아닐 경우에는 이제 위에서 정의한 struct 타입의 인스턴스에 넣어주면... 성공!!

 

2-2. Alamofire로 데이터 파싱하기

1. AF.request를 사용할 때 헤더정보를 request의 매개변수로 정의해서 보내기!!

func getDataUsingAF(){
    let headers = ["Content-Type":"application/json;charset=utf-8"]
    let call = AF.request(url,method: .get, encoding: JSONEncoding.default, headers: headers)
}

2. response 메서드를 통해 원하는 타입의 형태로 데이터를 전달받기

func getDataWithAF() {
	...
    //위에 이어서
	call.responseJSON{ res in
     do{
	    guard let jsonObject = try res.result.get() as? NSDictionary else {
	        NSLog("res is nil")
	        return
    	}
    }catch let e as NSError{
         NSLog("An error found : \(e.localizedDescription)")
    }
}

이렇게 데이터를 파싱해 올 수 있고.

AF.reqeust(...).responseJSON{ res in ...} 으로 사용할 수도 있습니다.