ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 날씨앱만들기 (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에서 호출해준다. 

     

     

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