52. 스파르타 코딩 클럽 - 봄여어름갈겨어울 #2 (날씨앱)
51. 스파르타 코딩 클럽 - 봄여어름갈겨어울 #1 (날씨앱)🌤️ 봄여어름갈겨어울 (심화 팀 프로젝트)최종 프로젝트 전 마지막 팀 프로젝트인 심화 주차 팀 프로젝트가 오늘 시작되었다.기간은 5월
coding-pill.tistory.com
🌤️ 봄여어름갈겨어울 (심화 팀 프로젝트)
[ 목차 ]
1. 오늘 작업 내용
2. Trouble Shooting
3. TIL
👨🏻💻 오늘 작업 내용
[ 1. NetworkManager 코드 수정 - 입력받은 위도, 경도를 사용하기 ]
[ 1-1. 외부에서 위도와 경도를 파라미터로 받아서 urlQueryItems를 리턴하는 함수를 추가
// urlQueryItems을 리턴하는 함수
func makeUrlQueryItems(lat: Double, lon: Double) -> [URLQueryItem] {
return [
URLQueryItem(name: "lat", value: String(lat)), // 위도
URLQueryItem(name: "lon", value: String(lon)), // 경도
URLQueryItem(name: "appid", value: apiKey), // apiKey 추가
URLQueryItem(name: "units", value: "metric") // 섭씨로 데이터 받기
]
}
[ 1-2. fetchCurrentWeatherData 메서드를 파라미터가 2개 있는 메서드로 변경 ]
// 서버에서 현재 날씨를 받아오는 메서드
func fetchCurrentWeatherData(lat: Double, lon: Double) -> Single<(WeatherResponse, String)> {
return Single.create { single in
var urlComponents = URLComponents(string: "https://api.openweathermap.org/data/2.5/weather")
urlComponents?.queryItems = self.makeUrlQueryItems(lat: lat, lon: lon)
guard let url = urlComponents?.url else {
print("잘못된 URL")
single(.failure(AFError.invalidURL(url: "")))
return Disposables.create()
}
self.fetchDataByAlamofire(url: url) { (result: Result<WeatherResponse, AFError>) in
switch result {
// 네트워크 통신 성공시
case .success(let weatherResponse):
let imageUrl = "https://openweathermap.org/img/wn/\(weatherResponse.weather[0].icon)@2x.png"
single(.success((weatherResponse, imageUrl))) // 성공시 날씨 정보와 아이콘 이미지 url을 방출
// 네트워크 통신 실패시
case .failure(let error):
print("데이터 로드 실패: \(error)")
single(.failure(error)) // 실패시 에러 방출
}
}
return Disposables.create() // Single 종료
}
}
fetchCurrentWeatherData 메서드 내부에서 urlQueryItems를 추가하기 위해
self.makeUrlQueryItems(lat: Double, lon: Double) 메서드를 사용
[ 1-3. fetchForeCastData 메서드를 파라미터가 2개 있는 메서드로 변경 ]
// 서버에서 5일 간 날씨 예보 데이터를 불러오는 메서드
func fetchForeCastData(lat: Double, lon: Double) -> Single<WeatherForecast> {
return Single.create { single in
var urlComponents = URLComponents(string: "https://api.openweathermap.org/data/2.5/forecast")
urlComponents?.queryItems = self.makeUrlQueryItems(lat: lat, lon: lon)
guard let url = urlComponents?.url else {
print("잘못된 URL")
single(.failure(AFError.invalidURL(url: "")))
return Disposables.create() // error를 방출하고 종료
}
self.fetchDataByAlamofire(url: url) { (result: Result<WeatherForecast, AFError>) in
switch result {
// 네트워크 통신 성공시
case .success(let weatherForecast):
single(.success(weatherForecast)) // 결과를 방출
// 네트워크 통신 실패시
case .failure(let error):
print("데이터 로드 실패: \(error)")
single(.failure(error)) // 에러 방출
}
}
return Disposables.create() // Single 종료
}
}
fetchForeCastData 메서드 내부에서 urlQueryItems를 추가하기 위해
self.makeUrlQueryItems(lat: Double, lon: Double) 메서드를 사용
[ 2. NetworkManager PR 및 Merge ]
[ 3. NetworkTestViewController 에서 Network Test ]
import UIKit
import RxSwift
import SnapKit
import Alamofire
class NetworkTestViewController: UIViewController {
var disposeBag = DisposeBag()
let network = NetworkManager.shared
private let currentWeatherLabel: UILabel = {
let label = UILabel()
label.text = ""
label.numberOfLines = 0
label.textAlignment = .center
return label
}()
private let imageView: UIImageView = {
let imageView = UIImageView()
imageView.contentMode = .scaleAspectFit
imageView.backgroundColor = .lightGray
return imageView
}()
private let forecastWeatherLabel: UILabel = {
let label = UILabel()
label.text = ""
label.numberOfLines = 0
label.textAlignment = .center
return label
}()
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .white
// 현재 날씨 네트워크 통신 테스트
fetchCurrentWeatherResponse()
// 날씨 예보 네트워크 통신 테스트
fetchForeCastResponse()
// 화면에 표시 테스트
configureUI()
}
func fetchCurrentWeatherResponse() {
network.fetchCurrentWeatherData(lat: 37.5, lon: 126.9)
.subscribe { (weather, imageUrl) in
print("날씨 정보 : \(weather)")
self.currentWeatherLabel.text = "현재 기온 : \(Int(weather.main.temp))°C"
print("날씨 아이콘 주소 : \(imageUrl)")
AF.request(imageUrl).responseData { response in
if let data = response.data, let image = UIImage(data: data) {
DispatchQueue.main.async {
self.imageView.image = image
}
}
}
} onFailure: { error in
print("에러 발생 : \(error)")
}.disposed(by: disposeBag)
}
func fetchForeCastResponse() {
network.fetchForeCastData(lat: 37.5, lon: 126.9)
.subscribe { weather in
print("5일간 날씨 예보 : \(Int(weather.list[0].main.temp))°C")
self.forecastWeatherLabel.text = "5일간 날씨 예보 기온 : \(weather.list[0].main.temp)"
} onFailure: { error in
print("에러 발생 : \(error)")
}.disposed(by: disposeBag)
}
}
🎯 Trouble Shooting
[ 1. NetworkManager 작성을 완료하고, 테스트를 위해 NetworkTestViewController를 만들어서 빌드를 했는데 apiKey를 찾지 못하는 에러가 발생 ]
- 이유 : 왜 인지 모르겠지만 (아마 dev 브랜치를 pull 한 뒤로 예상함) ApiKey를 넣어뒀던 Secret.xcconfig 파일이 내 프로젝트 폴더 내에 보이지 않음
- 해결 방법 : 1. 파인더로 봄여어름갈겨어울 프로젝트 폴더에 들어간 뒤 안에 있는 Secret.xcconfig 파일을 Xcode 내 프로젝트 폴더 안으로 드래그하여 넣어줌. 2. 다시 타겟 설정해 줌
✓ TIL
한 줄 TIL : RxSwift 이해에 한 발 다가선 오늘
내일은 팀원분과 함께 ViewModel 연결하는 작업을 해보려고 한다.
'스파르타 코딩 클럽 - iOS 스타터 6기 > 본 캠프' 카테고리의 다른 글
55. 스파르타 코딩 클럽 - 봄여어름갈겨어울 #5 (날씨앱) (0) | 2025.05.26 |
---|---|
54. 스파르타 코딩 클럽 - 봄여어름갈겨어울 #4 (날씨앱) (0) | 2025.05.23 |
52. 스파르타 코딩 클럽 - 봄여어름갈겨어울 #2 (날씨앱) (0) | 2025.05.21 |
51. 스파르타 코딩 클럽 - 봄여어름갈겨어울 #1 (날씨앱) (0) | 2025.05.20 |
50. 스파르타 코딩 클럽 - BookSearchApp #2 (0) | 2025.05.16 |