Tric : URL로 OpenAPI가져오기(json), isHidden
기능 : 도시 이름을 TextField에 입력하면 가져오기/잘못 입력 시 Alert 메세지 표시
URLSession : HTTP / HTTPS 기반 요청을 처리하기 위한 클래스 및 클래스의 세트 모음
→ html문서를 주고 받는데 쓰이는 통신 Protocol
→ 특정 url을 이용하여 data를 다운로드 !
(1) TextField에 도시이름을 입력한다.
(2) 날씨가져오기 버튼을 눌러 API를 가져온다.
(3) API가 Fetch되면 WeatherInformation 배열에 담기고 이를 StoryBoard에 적용시킨다.
(4) 도시 이름 오 기입시, 해당 메세지는 ErrorMessage 배열에 담기고 이를 Alert로 표시한다.
각 라벨들을 Stack View로 만들어 구분하기 - 전체 Stack View로 만들기
부모 Stack View Aligment : Center - spacing : 10
각 Child Stack View 속성 설정
부모 Stack View : 날씨 가져오기 이전엔 보여지면 안되므로 Hidden 속성으로 감추기
각 Label들 IBOulet 설정, 날씨가져오기 버튼은 IBAction.
struct WeatherInformation: Codable {
let weather: [Weather] // json파일에서 weather는 배열이므로 밑에 처럼 타입 선언을 한 것
let temp: Temp
let name: String
enum CodingKeys: String, CodingKey {
case weather
case temp = "main"
case name
}
} // json 인코딩, 디코딩 가능 weather informaiton 객체 <-> json
// 날씨 정보 json 파일을 weather informaiton struct로 변환하는 작업(디코딩)
struct Weather: Codable {
let id: Int
let main: String
let description: String
let icon: String
}
// json 파일을 변환하고자 하면 , json파일의 key와 사용자가 정의한 struct의 타입이 일치해야!
struct Temp: Codable {
let temp: Double
let feelsLike: Double
let minTemp: Double
let maxTemp: Double
enum CodingKeys: String, CodingKey {
case temp
case feelsLike = "feels_like"
case minTemp = "temp_min"
case maxTemp = "temp_max"
}
// json파일과 구조체에 선언된 이름이 달라도 Mappint될수 있도록,
// CodingKey 프로토콜을 채택하는 열거형 선언
}
@IBAction func tapFetchWeatherButton(_ sender: UIButton) {
if let cityName = self.cityNameTextField.text {
self.getCurrentWeather(cityName: cityName)
self.view.endEditing(true) // 버튼 눌리면 키보드 내려가는 기능
}
}
.
.
.
func getCurrentWeather(cityName: String) {
guard let url = URL(string: "https://api.openweathermap.org/data/2.5/weather?q=\(cityName)&appid=5448715390df41aed509eef3faa3053b") else { return }
let session = URLSession(configuration: .default)
session.dataTask(with: url) { data, response, error in
guard let data = data, error == nil else { return } // 요청 성공 시 다음라인 가도록
let decoder = JSONDecoder() // json 객체에서 data 유형의 인스턴스로 디코딩하는 객체! Decodable, Codable 프로토콜을 준수하는 라인!
let weatherInformation = try? decoder.decode(WeatherInformation.self, from: data)
// 1st Parameter : json을 매핑시켜줄 Codable Protocol을 준수하는 사용자 정의 타입(구조체 만들어 둔거)
// 2nd Parameter : 서버에서 응답받은 json 데이터
debugPrint(weatherInformation)
}.resume() // dataTask.resume() 호출하여 작업 실행!
}
}
func configureView(weatherInformation: WeatherInformation) {
self.cityNameLabel.text = weatherInformation.name
if let weather = weatherInformation.weather.first {
self.weatherDiscription.text = weather.description
}
self.tempLabel.text = "\(Int(weatherInformation.temp.temp - 273.15))°C"
self.minTempLabel.text = "\(Int(weatherInformation.temp.minTemp - 273.15))°C"
self.maxTempLabel.text = "\(Int(weatherInformation.temp.maxTemp - 273.15))°C"
} // 함수안에서 쓰일 parameter weatherInformation는 앞에서 정의한 WeatherInformation 배열에 저장된 값들이다!
.
.
.
func getCurrentWeather(cityName: String) {
guard let url = URL(string: "https://api.openweathermap.org/data/2.5/weather?q=\(cityName)&appid=5448715390df41aed509eef3faa3053b") else { return }
let session = URLSession(configuration: .default)
session.dataTask(with: url) { [weak self] data, response, error in
guard let data = data, error == nil else { return } // 요청 성공 시 다음라인 가도록
let decoder = JSONDecoder() // json 객체에서 data 유형의 인스턴스로 디코딩하는 객체! Decodable, Codable 프로토콜을 준수하는 라인!
let weatherInformation = try? decoder.decode(WeatherInformation.self, from: data)
// 1st Parameter : json을 매핑시켜줄 Codable Protocol을 준수하는 사용자 정의 타입(구조체 만들어 둔거)
// 2nd Parameter : 서버에서 응답받은 json 데이터
DispatchQueue.main.async {
self?.weatherStackView.isHidden = false
self?.configureView(weatherInformation: weatherInformation)
}
// 네트워크 작업은 별도의 Thread에서 진행되고 응답이 온다해도 main Thread로 오지않기에
// Main Thread로 오도록 설정!
}.resume() // dataTask.resume() 호출하여 작업 실행!
}
struct ErrorMessage: Codable {
let message: String
}
func getCurrentWeather(cityName: String) {
.
.
let successRange = (200..<300)
guard let data = data, error == nil else { return }
// 요청 성공 시 다음라인 가도록
let decoder = JSONDecoder()
// json 객체에서 data 유형의 인스턴스로 디코딩하는 객체! Decodable, Codable 프로토콜을 준수하는 라인!
if let response = response as? HTTPURLResponse, successRange.contains(response.statusCode) {
guard let weatherInformation = try? decoder.decode(WeatherInformation.self, from: data) else { return }
// 1st Parameter : json을 매핑시켜줄 Codable Protocol을 준수하는 사용자 정의 타입(구조체 만들어 둔거)
// 2nd Parameter : 서버에서 응답받은 json 데이터
DispatchQueue.main.async { // 메인 Thread에서 작업하도록
self?.weatherStackView.isHidden = false
self?.configureView(weatherInformation: weatherInformation)
}
} else {
guard let errorMessage = try? decoder.decode(ErrorMessage.self, from: data) else { return }
DispatchQueue.main.async {
self?.showAlert(mesaage: errorMessage.message)
}
// 1st Parameter : json을 매핑시켜줄 Codable Protocol을 준수하는 사용자 정의 타입(구조체 만들어 둔거)
// 2nd Parameter : 서버에서 응답받은 json 데이터
}
}
func showAlert(mesaage: String){
let alert = UIAlertController(title: "Error", message: mesaage, preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "확인", style: .default, handler: nil))
self.present(alert, animated: true, completion: nil)
}
URLSession : URLSessionConfiguration을 통해 생성가능
공유 세션 : URlSession.shared( )
기본 세션 : URlSession(configuration: .defalut)
임시 세션 : URlSession(configuration: .ephemeral)
백그라운드 세션 : URlSession(configuration: .background)
→ 이렇게 생성된 URLSession은 한개 이상의 URLSessionTask을 생성가능하며, 이를 통해 실제 서버와 통신할 수 있음
URLSessionDataTask : 짧고 빈번한 요청
URLSessionUploadTask
URLSessionDownloadTask
URLSessionStreamTask
URLSessionWebSocketTask