ios 32일차

bin·2026년 2월 11일

회고

오늘은 강의영상을 마무리 하고 개인 과제를 시작했다. 늘 하던대로 한번 요구사항에 맞춰서 일단 동작하도록 빠르게 한번 만들어본 후 리팩토링을 거치며 완성할 것이다.

강의 영상에 관한 기록

날씨앱(1)

Alamofire를 사용하지 않고 구현한다.
기본적인 fetchData 메서드를 생성한다. 이후 fetchData를 이용하는 fetchCurrentWeatherResult와 fetchForecastWeatherResult를 구현한다.
fetchData는 통신을 하기 위한 설정이라고 생각하면 된다. 이 경로를 통해 데이터를 받아오고 디코딩하는 과정까지를 정의한다.

1. fetchData()

extension ViewController {
    private func fetchData<T: Decodable>(url: URL, completion: @escaping(T?) -> Void) {
        let session = URLSession(configuration: .default)
        session.dataTask(with: url) { data, response, error in
            guard let data, error == nil else {
                print("데이터 로드 실패")
                completion(nil)
                return
            }
            let successRange: Range = (200..<300)
            if let response = response as? HTTPURLResponse, successRange.contains(response.statusCode) {
                guard let decodedData = try? JSONDecoder().decode(T.self, from: data) else {
                    print("JSON 디코딩 실패")
                    completion(nil)
                    return
                }
                completion(decodedData)
            } else {
                print("응답 오류")
                completion(nil)
            }
        }.resume()
    }
}

2. fetchCurrentWeatherResult()

url을 입력하고 해당 url을 이용하여 fetchData를 진행하여 받아온 데이터를 실제 UI에 사용할 수 있도록 정의한다.

    private func fetchCurrentWeatherResult() {
        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/payload/api/media/file/\(result.weather[0].icon)@2x.png") else { return }
            if let data = try? Data(contentsOf: imageUrl), let image = UIImage(data: data) {
                self.imageView.image = image
            }
        }
    }

날씨앱(2)

위에서 구현한 fetchData를 Alamofire를 이용하여 구현하면 아래와 같다.

1. fetchDataByAlamofire()

extension ViewController {
    private func fetchDataByAlamofire<T: Decodable>(url: URL, completion: @escaping(Result<T, AFError>) -> Void) {
        AF.request(url).responseDecodable(of: T.self) { response in
            completion(response.result)
        }
    }
}

또한 fetchCurrentWeatherResult를 Alamofire로 구현하면 아래와 같다.

2. fetchCurrentWeatherResultByAlamofire()

    private func fetchCurrentWeatherResultbyAlamofire() {
        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
        }
        fetchDataByAlamofire(url: url) { [weak self] (result: (Result<CurrentWeatherResult, AFError>)) in
            guard let self else { return }
            switch result {
            case .success(let result):
                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/payload/api/media/file/\(result.weather[0].icon)@2x.png") else { return }
                AF.request(imageUrl).responseData { response in
                    if let data = response.data, let image = UIImage(data: data) {
                        self.imageView.image = image
                    }
                }
            case .failure(let error):
                print("에러 \(error)")
            }
        }
    }

0개의 댓글