-
날씨앱만들기 (3) UI 구성 2카테고리 없음 2024. 7. 15. 16:45
서버데이터를 불러오는 메서드까지 작성했다면
날씨앱만들기 (2) UI 구성 1
일단은 UI 구성이 잘 되었는지 확인이 필요하니까 임의의 컬러, 텍스트값을 넣어서 UI 구성을 해준다. 더보기import UIKitimport SnapKitclass ViewController: UIViewController { //현재 위치한 도시를 알려주는 라
bluewiper.tistory.com
이제는 서버에서 현재 날씨 데이터를 불러오는 메서드를 작성해야 한다.
아래는 ViewController인데 여기서 함수만 일단 만들어주고, 미리 만들어 놓은 CurrentWeatherData 화면에서 작업을 이어간다.
//서버에서 현재 날씨 데이터를 불러오는 메서드 private func fetchCurrentWeatherData() { }
이전에 API 데이터를 불러왔을 때 어떤 형태로 받았는지 확인하고, 실질적으로 사용할 만한 데이터의 값을 추리고,
미리 만들어둔 CurrentWeatherResult에 해당 데이터 형태에 맞는 구조체를 만들어 준다.
아래는 API 사이트에서 제공하는 API response 예시이다.
이중에서 weather, main 부분만 쓸 예정이다.
CurrentWeatherResult.swift
import Foundation //Codable을 채택하는 구조체 생성 struct CurrentWeatherResult: Codable { let weather: [Weather] let main: WeatherMain } struct Weather: Codable { let id: Int let main: String let description: String let icon: String } struct WeatherMain: Codable { let temp: Double let tempMin: Double let tempMax: Double enum CodingKeys: String, CodingKey { case temp case tempMin = "temp_min" case tempMax = "temp_max" } }
다시 private func fetchCurrentWeatherData()로 돌아가서 작성을 이어간다.
//서버에서 현재 날씨 데이터를 불러오는 메서드 private func fetchCurrentWeatherData() { var urlComponents = URLComponents(string: "https://api.openweathermap.org/data/2.5/weather") }
맨 위에서 urlComponent를 살펴보면 query 이전까지의 url만 복사해서 불러왔다.
currentWeather, forecastWeather의 url 커리가 똑같이 사용되고 있어서 각각 적어주지 않고, 불러올 수 있도록 쿼리에 대한 프로퍼티를 생성해준다.
API call을 확인해서 필요한 값을 파악한다. 우리는 위치를 확인하기 위해 lat, lon이 필요하고, api key를 넣을 수 있도록
appid, 그리고 metric 시스템을 적용하기 위해 units를 쿼리아이템으로 만들어줄 것이다.
ViewController.swift
프로퍼티들이 모여있는 곳에 정의해줬다.
//URL 쿼리아이템들(Current Weather, Forcast Weather 두가지이지만 똑같은 쿼리를 쓰는 URL을 쓰기 때문에 미리 정의 //서울역 위경도 private let urlQueryItems: [URLQueryItem] = [ URLQueryItem(name: "lat", value: "37.5"), URLQueryItem(name: "lon", value: "126.9"), URLQueryItem(name: "appid", value: "dd36828ea83a2a55cfdfab1d88773876"), URLQueryItem(name: "units", value: "metric") ]
ViewController.swift
//서버에서 현재 날씨 데이터를 불러오는 메서드 private func fetchCurrentWeatherData() { var urlComponents = URLComponents(string: "https://api.openweathermap.org/data/2.5/weather") urlComponents?.queryItems = self.urlQueryItems guard let url = urlComponents?.url else { print("잘못된 url") return } fetchData(url: url) { [weak self] (result: CurrentWeatherResult?) in guard let self, let result else { return } // 메인스레드에서 작동하도록 하는 메서드 DispatchQueue.main.async { self.tempLabel.text = "\(Int(result.main.temp))°C" // 서버에서 가져온 현재 날씨 데이터가 불러와짐 self.tempMinLabel.text = "최저: \(Int(result.main.tempMin))°C" self.tempMaxLabel.text = "최고: \(Int(result.main.tempMax))°C" } guard let imageUrl = URL(string: "https://openweathermap.org/img/wn/\(result.weather[0].icon)@2x.png") else { return } // image를 로드하는 작업은 백그라운드 쓰레드 작업 if let data = try? Data(contentsOf: imageUrl) { if let image = UIImage(data: data) { DispatchQueue.main.async { self.imageView.image = image } } } } }
* Notice
서버데이터를 불러오는 작업은 백그라운드 스레드에서 실행되는데
UI 작업은 메인 스레드에서 해야하기 때문에 DispatchQuene.main.async{} 코드 안에서 UI 작업을 해준다.
이렇게 작업해주면 기존에 tempLabel 등의 text를 임의로 지정해줬던 곳에 서버 데이터가 들어오게 된다.
예시
//기온을 나타내는 라벨 private let tempLabel: UILabel = { let label = UILabel() label.text = "20도" label.textColor = .white label.font = .boldSystemFont(ofSize: 50) return label }()
DispatchQueue.main.async { self.tempLabel.text = "\(Int(result.main.temp))°C" }
UI 코드가 완료 되면 viewDidLoad에서 호출해준다.
그럼 이 화면에서 날씨 이미지까지 서버데이터를 통해 구현된다.