데이터 모델
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")
[Swift] 간단한 날씨 앱 만들어보기 02 (Swift OpenWeatherMap)
[Swift] 간단한 날씨 앱 만들어보기 02 (Swift OpenWeatherMap)
velog.io
'Language > Swift 날씨 앱' 카테고리의 다른 글
Swift 날씨 앱 만들기 (1) (0) | 2022.07.04 |
---|
Comment