ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Alamofire를 이용하여 데이터 불러오기
    카테고리 없음 2024. 7. 15. 14:57

    Alamofire는

    더보기

    Swift로 작성된 강력하고 사용하기 쉬운 네트워킹 라이브러리입니다. 주로 iOS 및 macOS 애플리케이션에서 HTTP 네트워킹 작업을 간단하고 직관적으로 수행할 수 있도록 도와줍니다. Alamofire는 다음과 같은 주요 기능을 제공합니다:

    주요 기능

    1. HTTP 요청 및 응답:
      • GET, POST, PUT, DELETE 등의 다양한 HTTP 메서드를 쉽게 사용할 수 있습니다.
      • JSON, plist, XML 등 다양한 형식의 응답 데이터를 자동으로 파싱할 수 있습니다.
    2. 네트워크 요청 설정:
      • URL, 매개변수, 헤더 등을 쉽게 구성할 수 있습니다.
      • URLSessionConfiguration을 사용하여 네트워크 세션을 커스터마이즈할 수 있습니다.
    3. 응답 처리:
      • 데이터 응답, JSON 응답, String 응답 등 다양한 방식으로 응답을 처리할 수 있습니다.
      • 응답 검증 및 에러 처리 기능을 제공합니다.
    4. 파일 업로드 및 다운로드:
      • 멀티파트 파일 업로드, 백그라운드 다운로드 등 파일 전송 작업을 간편하게 수행할 수 있습니다.
      • 다운로드 진행 상황을 추적할 수 있습니다.
    5. 네트워크 리치성(Richness):
      • 네트워크 리치성을 판단하고, 연결 상태 변화를 감지할 수 있습니다.
      • 네트워크 요청 재시도, 연결 시간 초과 등의 네트워크 관리 기능을 제공합니다.

     

    Alamofire는 네트워킹 요청의 응답을 처리할 때 Result 타입을 사용하여 성공과 실패를 구분합니다.

     

    switch 구문을 사용하여 성공과 실패 케이스를 처리하는 방식을 채택하여

     

     

    • .success(let data):
      • 요청이 성공하면 response.result는 .success 상태가 되고, data에 응답 데이터가 포함됩니다.
      • 여기서 data는 JSON 형식일 수 있으며, 이를 파싱하여 사용할 수 있습니다.
    • .failure(let error):
      • 요청이 실패하면 response.result는 .failure 상태가 되고, error에 에러 정보가 포함됩니다.
      • 네트워크 문제, 서버 응답 문제, 데이터 파싱 문제 등 다양한 이유로 요청이 실패할 수 있습니다.
      • 여기서 error를 처리하여 사용자에게 오류 메시지를 표시하거나, 재시도 로직을 구현할 수 있습니다.

     

     

     

    일반적으로 서버데이터를 불러오는 메서드

    // 서버 데이터를 불러오는 메서드
        private func fetchData<T: Decodable>(url: URL, completion: @escaping (T?) -> Void) {
            let session = URLSession(configuration: .default)
            session.dataTask(with: URLRequest(url: url)) { data, response, error in
                guard let data, error == nil else {
                    print("데이터 로드 실패")
                    completion(nil)
                    return
                }
                // http status code 성공 범위는 200번대
                let successRange = 200..<300
                //HTTPURLResponse 안에 http status code를 깔기 위해 타입 캐스팅을 해준다.
                if let response = response as? HTTPURLResponse, successRange.contains(response.statusCode) {
                    // 받은 데이터가 JSON 형태일테니 Swift 형태로 디코딩해준다.
                    guard let decodedData = try? JSONDecoder().decode(T.self, from: data) else {
                        print("JSON 디코딩 실패")
                        completion(nil)
                        return
                    }
                    // guard let decodedData가 성공했을 경우
                    completion(decodedData)
                    //성공 범위 안에 들지 못한다면(200번대)
                } else {
                    print("응답 오류")
                    completion(nil)
                }
            }.resume() // resume해야 작동한다.
        }

     

     

     

    Alamofire를 이용해 서버데이터를 불러오는 메서드

        //Alamofire를 이용해 서버 데이터를 불러오는 메서드
        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)
            }
        }

     

    Alamofire이 설치가 되어 있지 않다면? 

    더보기

    Alamofire를 위한 서버데이터 불러오기 

     

    프레임워크에 Alamofire를 불러온다. 

     

    검색했을 때 안 나오면, 

     

    깃허브에서 url을 따서 검색해준다. 

    Alamofire url : https://github.com/Alamofire/Alamofire

     

    좌측과 중앙에서 Alamofire 프레임워크가 잘 다운로드 받아진 것을 확인할 수 있다. 

     

    ViewController에 import Alamofire를 해주고, 위 코드를 작성한다. 

     

    *** Snapkit 다운로드 받을 때도 문제였는데 Daynamic까지 깔았을 때 

    No such file or directory: '/Users/sweetyejin/Library/Developer/Xcode/DerivedData/weatherAppPractice-ewpajbpjzttwjthftdcfwnvoswst/Build/Products/Debug-iphonesimulator/PackageFrameworks/AlamofireDynamic.framework/AlamofireDynamic' 이런류의 오류가 뜨면 프레임워크에서 Dynamic만 삭제해주면 오류 없이 실행 된다. 다운로드 받는 방법이 여러가지가 있는데 위와 같은 방법으로 할 때 적용되는  방법이다. 

     private func fetchCurrentWeatherData()에서 fetchData를 받아올 때 Alamofire로 서버를 불러올 수 있도록 다음과 같이 코드를 써볼 수 있다. 

     

    기존

     //서버에서 현재 날씨 데이터를 불러오는 메서드
        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
                        }
                    }
                }
            }
        }

     

    alamofire import 후

        //서버에서 현재 날씨 데이터를 불러오는 메서드
        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
            }
            
            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/img/wn/\(result.weather[0].icon)@2x.png") else {
                        return
                    }
                    // AlamoFire를 사용한 이미지 로드
                    AF.request(imageUrl).responseData { response in
                        if let data = response.data, let image = UIImage(data: data) {
                            DispatchQueue.main.async {
                                self.imageView.image = image
                            }
                        }
                    }
                    
                case .failure(let error):
                    print("데이터 로드 실패: \(error)")
                }
                
            }
     
        }

     

    마찬가지로  private func fetchForecastWeatherData()에서 fetchData를 받아올 때 Alamofire로 서버를 불러올 수 있도록 다음과 같이 코드를 써볼 수 있다. 

     

    AlamoFire 적용 전

        // 서버에서 5일 간 날씨 데이터를 불러오는 메서드
        private func fetchForecastData() {
            var urlComponents = URLComponents(string: "https://api.openweathermap.org/data/2.5/forecast")
            urlComponents?.queryItems = self.urlQueryItems
            
            guard let url = urlComponents?.url else {
                print("잘못된 URL")
                return
            }
            fetchData(url: url) { [weak self] (result: ForecastWeatherResult?) in
                guard let self, let result else { return }
                
                // 콘솔에다가 데이터 잘 불러왔는지 찍어보기
                for forecastWeather in result.list {
                    print("\(forecastWeather.main)\n\(forecastWeather.dtTxt)\n\n")
                }
                DispatchQueue.main.async {
                    self.dataSource = result.list
                    self.tableView.reloadData() // reloadData()를 해야 반영 됨
                }
            }
        }

     

    적용 후 

        // 서버에서 5일 간 날씨 데이터를 불러오는 메서드
        private func fetchForecastData() {
            var urlComponents = URLComponents(string: "https://api.openweathermap.org/data/2.5/forecast")
            urlComponents?.queryItems = self.urlQueryItems
            
            guard let url = urlComponents?.url else {
                print("잘못된 URL")
                return
            }
            
            fetchDataByAlamofire(url: url) { [weak self] (result: Result<ForecastWeatherResult, AFError>) in
                
                guard let self else { return }
                switch result {
                case .success(let result):
                    DispatchQueue.main.async {
                        self.dataSource = result.list
                        self.tableView.reloadData()
                    }
                    
                case .failure(let error):
                    print("데이터 로드 실패: \(error)")
                }
                
            }
       }