-
Alamofire를 이용하여 데이터 불러오기카테고리 없음 2024. 7. 15. 14:57
Alamofire는
더보기Swift로 작성된 강력하고 사용하기 쉬운 네트워킹 라이브러리입니다. 주로 iOS 및 macOS 애플리케이션에서 HTTP 네트워킹 작업을 간단하고 직관적으로 수행할 수 있도록 도와줍니다. Alamofire는 다음과 같은 주요 기능을 제공합니다:
주요 기능
- HTTP 요청 및 응답:
- GET, POST, PUT, DELETE 등의 다양한 HTTP 메서드를 쉽게 사용할 수 있습니다.
- JSON, plist, XML 등 다양한 형식의 응답 데이터를 자동으로 파싱할 수 있습니다.
- 네트워크 요청 설정:
- URL, 매개변수, 헤더 등을 쉽게 구성할 수 있습니다.
- URLSessionConfiguration을 사용하여 네트워크 세션을 커스터마이즈할 수 있습니다.
- 응답 처리:
- 데이터 응답, JSON 응답, String 응답 등 다양한 방식으로 응답을 처리할 수 있습니다.
- 응답 검증 및 에러 처리 기능을 제공합니다.
- 파일 업로드 및 다운로드:
- 멀티파트 파일 업로드, 백그라운드 다운로드 등 파일 전송 작업을 간편하게 수행할 수 있습니다.
- 다운로드 진행 상황을 추적할 수 있습니다.
- 네트워크 리치성(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)") } } }
- HTTP 요청 및 응답: