적당한 고통은 희열이다

- 댄 브라운 '다빈치 코드' 중에서

Project/ToyProject_Couple App

[Swift iOS] Open Weather Map API 사용해 날씨 데이터 불러오기

hongssup_ 2021. 2. 9. 19:18
반응형

OpenWeatherMap 사이트 : openweathermap.org/api

요기서 필요한 API를 가져올 수 있는데, 나는 현재 날씨를 받아오기 위해 Current Weather Data를 받아왔다가 아직 구현할 필요는 없기만 혹시나 추후 날씨 예보도 추가하고 싶을까봐 One Call API로 바꿨다. 

One Call API 에는 현재 날씨, 예보, 과거 데이터가 다 포함되어 있고, 원하는 데이터만 불러올 수도 있기 때문에 범용을 위해 이걸 사용하는 것을 추천. 

 

API call :

" https://api.openweathermap.org/data/2.5/onecall?lat=37.5683&lon=126.9778&exclude=minutely,alerts&appid={API key}&units=metric"

 

1. 사이트 로그인 후 개인 API key 받아오기

2. API url 링크 들어가서 JSON 데이터 보고, 원하는 데이터들로 날씨 Model 만들기

3. API url 불러와 JSON 데이터 디코딩하여 읽어들이기

4. 원하는 데이터 화면에 표시하기

 

Model 폴더를 만들어 새로운 swift file을 추가해준다. API url 에서 JSON 데이터를 보고, 같은 구조로 내가 필요할 것 같은 인자들로만 날씨 데이터 모델을 만들어준다. 

// Weather.swift

import Foundation

struct WeatherResponse: Decodable {
    let timezone: String
    let current: Current

}

struct Current : Decodable{
    let temp: Double
    let feels_like: Double
    let clouds: Int
    let wind_speed: Double
    let weather: [Weather]
}

struct Weather: Decodable {
    let main: String
    let description: String
    let icon: String
}

 나는 JSON 데이터를 디코딩하는 작업을 Service 라는 폴더를 따로 만들어서 처리해주었다. 

// WeatherService.swift

import Foundation

enum NetworkError: Error {
    case badUrl
    case noData
    case decodingError
}

class WeatherService {
    
    let url = URL(string: "") //개인 API key를 넣은 API call 넣어주기
    
    func getWeather(completion: @escaping (Result<WeatherResponse, NetworkError>) -> Void) {
        guard let url = url else {
            return completion(.failure(.badUrl))
        }
        URLSession.shared.dataTask(with: url) { data, response, error in
            guard let data = data, error == nil else {
                return completion(.failure(.noData))
            }
            let weatherResponse = try? JSONDecoder().decode(WeatherResponse.self, from: data)
            if let weatherResponse = weatherResponse {
                completion(.success(weatherResponse))
            } else {
                completion(.failure(.decodingError))
            }
        }.resume()
    }
}

그런 다음 나는 화면에 데이터를 표시하기 위해 viewWillAppear() 안에다 UI Update 코드를 넣어주었는데 사실 좋은 방법인지는 잘 모르겠다. 혹시 더 좋은 방법을 아시는 분은 좀 알려주시면 감사하게쑴당.. ㅎㅎㅎ

//WeatherViewController.swift

import Foundation
import UIKit

class WeatherViewController: UIViewController {

    var currentWeather: Current?
    var temperature: Double = 0.0
    var icon: String = ""
    let weatherLabel = UILabel()
    let weatherImage = UIImageView()
    
    // loadView() / viewDidLoad() 이용해 view를 만들어주고
    
    override func viewWillAppear(_ animated: Bool) {
        fetchWeather()
    }
    
    func fetchWeather() {
        WeatherService().getWeather { result in
            switch result {
            case .success(let weatherResponse):
                DispatchQueue.main.async {
                    self.currentWeather = weatherResponse.current
                    self.temperature = self.currentWeather?.temp ?? 0.0
                    self.weatherLabel.text = "temp: \(self.temperature)"
                    self.weatherImage.image = UIImage(named: self.currentWeather?.weather[0].icon ?? "01d")
                }
            case .failure(_ ):
                print("error")
            }
        }
    }
}

 

 

 

참고 사이트 : 유튜브, Github

728x90
반응형