Swift 날씨 앱 만들기 (2)

데이터 모델

Weather.swift

//  Weather.swift

import Foundation

struct WeatherResponse: Decodable {
    let weather: [Weather]
    let main: Main
    let name: String
}

struct Main: Decodable {
    let temp: Double
    let temp_min: Double
    let temp_max: Double
}

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

 

API 호출하고 리턴 받기

WeatherService.swift : 요청을 주고 결과 받기

//  WeatherService.swift

import Foundation

// 에러 정의
enum NetworkError: Error {
    case badUrl
    case noData
    case decodingError
}

class WeatherService {
    // .plist에서 API Key 가져오기
    private var apiKey: String {
        get {
            // 생성한 .plist 파일 경로 불러오기
            guard let filePath = Bundle.main.path(forResource: "APIKey", ofType: "plist") else {
                fatalError("Couldn't find file 'APIKey.plist'.")
            }
            
            // .plist를 딕셔너리로 받아오기
            let plist = NSDictionary(contentsOfFile: filePath)
            
            // 딕셔너리에서 값 찾기
            guard let value = plist?.object(forKey: "OPENWEATHERMAP_KEY") as? String else {
                fatalError("Couldn't find key 'OPENWEATHERMAP_KEY' in 'APIKey.plist'.")
            }
            return value
        }
    }
    
    func getWeather(completion: @escaping (Result<WeatherResponse, NetworkError>) -> Void) {
        
        // 1. URL - API 호출을 위한 URL
        let url = URL(string: "https://api.openweathermap.org/data/2.5/weather?q=seoul&appid=\(apiKey)")
        guard let url = url else {
            return completion(.failure(.badUrl))
        }
        
        // 2. URLSession 만들고 3. task 주기
        URLSession.shared.dataTask(with: url) { data, response, error in
            guard let data = data, error == nil else {
                return completion(.failure(.noData))
            }
            
            // Data 타입으로 받은 리턴을 디코드
            let weatherResponse = try? JSONDecoder().decode(WeatherResponse.self, from: data)

            // 성공
            if let weatherResponse = weatherResponse {
                print(weatherResponse)
                completion(.success(weatherResponse)) // 성공한 데이터 저장
            } else {
                completion(.failure(.decodingError))
            }
        }.resume() // 4. dataTask 시작
    }
}

 

동작해보기

ViewController.swift

// ViewController.swift
import UIKit

class ViewController: UIViewController {
    // 받아온 데이터를 저장할 프로퍼티
    var weather: Weather?
    var main: Main?
    var name: String?
    
    override func viewDidLoad() {
        super.viewDidLoad()

        // data fetch
        WeatherService().getWeather { result in
            switch result {
            case .success(let weatherResponse):
                DispatchQueue.main.async {
                    self.weather = weatherResponse.weather.first
                    self.main = weatherResponse.main
                    self.name = weatherResponse.name
                }
            case .failure(_ ):
                print("error")
            }
        }
    }
}

 

데이터를 정상적으로 받은걸 확인

 

WeatherResponse(weather: [WeatherSDY.Weather(id: 721, main: "Haze", description: "haze", icon: "50n")], main: WeatherSDY.Main(temp: 302.86, temp_min: 298.84, temp_max: 303.93), name: "Seoul")

 

 

UI 세팅, 실행결과

 

해당 View들을 IBOutlet으로 ViewController에 연결(생략)

 

UI 세팅하는 함수

// ViewController.swift
private func setWeatherUI() {
    let url = URL(string: "https://openweathermap.org/img/wn/\(self.weather?.icon ?? "00")@2x.png")
    let data = try? Data(contentsOf: url!)
    if let data = data {
        iconImageView.image = UIImage(data: data)
    }
    tempLabel.text = "\(main!.temp)"
    maxTempLabel.text = "\(main!.temp_max)"
    minTempLabel.text = "\(main!.temp_min)"
}

 

success 호출

// ViewController.swift
override func viewDidLoad() {
    super.viewDidLoad()
    WeatherService().getWeather { result in
        switch result {
        case .success(let weatherResponse):
            DispatchQueue.main.async {
                self.weather = weatherResponse.weather.first
                self.main = weatherResponse.main
                self.name = weatherResponse.name
                self.setWeatherUI()
            }
        case .failure(_ ):
            print("error")
        }
    }
}

 

실행결과

 

섭씨로 바꾸기

OpenWeather API에서 제공하는 기본 온도 단위가 Kelvin 단위이기 때문에 우리가 평소에 사용하는 섭씨를 사용하려면 URL 뒤에

&units=metric 를 붙여주면 된다.

 

 let url = URL(string: "https://api.openweathermap.org/data/2.5/weather?q=seoul&appid=\(apiKey)&units=metric")

 

 

 

출처 : https://velog.io/@dlskawns96/Swift-%EA%B0%84%EB%8B%A8%ED%95%9C-%EB%82%A0%EC%94%A8-%EC%95%B1-%EB%A7%8C%EB%93%A4%EC%96%B4%EB%B3%B4%EA%B8%B0-02-Swift-OpenWeatherMap

 

[Swift] 간단한 날씨 앱 만들어보기 02 (Swift OpenWeatherMap)

[Swift] 간단한 날씨 앱 만들어보기 02 (Swift OpenWeatherMap)

velog.io

 

'Language > Swift 날씨 앱' 카테고리의 다른 글

Swift 날씨 앱 만들기 (1)  (0) 2022.07.04