카테고리 없음

날씨앱만들기 (3) UI 구성 2

bluewiper 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에서 호출해준다. 

 

 

그럼 이 화면에서 날씨 이미지까지 서버데이터를 통해 구현된다.