class NetworkManager {
static let shared = NetworkManager() // 싱글톤 패턴 인스턴스를 생성
private let apiKey = " API 키 " // API 키를 저장합니다.
private let baseUrl = "https://api.openweathermap.org/data/2.5" // API의 기본 URL을 저장합니다.
private init() {} // 외부에서 인스턴스를 생성하지 못하도록 private 생성자를 만듭니다.
}
private func fetchData<T: Decodable>(url: URL, completion: @escaping (T?) -> Void) {
let session = URLSession(configuration: .default) // 기본 설정으로 URLSession 인스턴스를 생성합니다.
session.dataTask(with: URLRequest(url: url)) { data, response, error in
guard let data = data, error == nil else {
print("데이터 로드 실패") // 데이터 로드 실패 시 메시지 출력
completion(nil) // nil 반환
return
}
let successRange = 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 디코딩 실패") // JSON 디코딩 실패 시 메시지 출력
completion(nil) // nil 반환
return
}
completion(decodedData) // 디코딩 성공 시 데이터를 반환
} else {
print("응답 오류") // 응답 오류 시 메시지 출력
completion(nil) // nil 반환
}
}.resume() // 요청 시작
}
func fetchCurrentWeatherData(lat: Double, lon: Double, completion: @escaping (CurrentWeatherResult?, UIImage?) -> Void) {
var urlComponents = URLComponents(string: "\(baseUrl)/weather")
urlComponents?.queryItems = [
URLQueryItem(name: "lat", value: "\(lat)"), // 위도
URLQueryItem(name: "lon", value: "\(lon)"), // 경도
URLQueryItem(name: "appid", value: apiKey), // API 키
URLQueryItem(name: "units", value: "metric") // 온도 단위를 섭씨로 설정
]
guard let url = urlComponents?.url else {
print("잘못된 URL") // URL 생성 실패 시 메시지 출력
completion(nil, nil) // completion 클로저를 통해 nil 반환
return
}
fetchData(url: url) { (result: CurrentWeatherResult?) in
guard let result = result else {
completion(nil, nil) // 실패 시 nil 반환
return
}
guard let icon = result.weather.first?.icon,
let imageUrl = URL(string: "https://openweathermap.org/img/wn/\(icon)@2x.png") else {
completion(result, nil) // 아이콘 URL 생성 실패 시 데이터만 반환
return
}
DispatchQueue.global().async {
if let data = try? Data(contentsOf: imageUrl), let image = UIImage(data: data) {
DispatchQueue.main.async {
completion(result, image) // 성공적으로 이미지 로드 시 이미지와 데이터를 반환
}
} else {
DispatchQueue.main.async {
completion(result, nil) // 이미지 로드 실패 시 데이터만 반환
}
}
}
}
}
func fetchForecastData(lat: Double, lon: Double, completion: @escaping (ForecastWeatherResult?) -> Void) {
var urlComponents = URLComponents(string: "https://api.openweathermap.org/data/2.5/forecast")
urlComponents?.queryItems = [
URLQueryItem(name: "lat", value: "\(lat)"), // 위도
URLQueryItem(name: "lon", value: "\(lon)"), // 경도
URLQueryItem(name: "appid", value: apiKey), // API 키
URLQueryItem(name: "units", value: "metric") // 온도 단위를 섭씨로 설정
]
guard let url = urlComponents?.url else {
print("잘못된 URL") // URL 생성 실패 시 메시지 출력
completion(nil) // completion 클로저를 통해 nil 반환
return
}
fetchData(url: url, completion: completion) // 제네릭을 활용해 다양한 타입의 데이터 처리가 가능
}
struct CurrentWeatherResult: Codable {
let weather: [Weather] // 날씨 정보 배열
let main: WeatherMain // 주요 날씨 정보 (온도, 습도 등)
let wind: Wind // 바람 정보 추가
let rain: Rain? // 강수량 정보 추가 (비가 오지 않으면 없음)
}
struct Weather: Codable {
let id: Int // 날씨 ID
let main: String // 날씨 상태 (예: "Clear")
let description: String // 날씨 설명 (예: "clear sky")
let icon: String // 날씨 아이콘의 파일명
}
struct WeatherMain: Codable {
let temp: Double // 현재 온도
let temp_min: Double // 최저 온도
let temp_max: Double // 최고 온도
let humidity: Int // 습도
let feels_like: Double // 체감 온도 추가
}
struct Wind: Codable {
let speed: Double // 풍속 (m/s)
let deg: Int // 풍향 (도)
let gust: Double? // 돌풍 속도 (옵셔널)
}
struct Rain: Codable {
let oneHour: Double? // 지난 1시간 동안의 강수량 (옵셔널)
let threeHour: Double? // 지난 3시간 동안의 강수량 (옵셔널)
enum CodingKeys: String, CodingKey {
case oneHour = "1h"
case threeHour = "3h"
}
}
struct ForecastWeatherResult: Codable {
let list: [ForecastWeather] // 날씨 예보 리스트
}
struct ForecastWeather: Codable {
let main: WeatherMain // 주요 날씨 정보 (온도, 습도 등)
let wind: Wind // 바람 정보 추가
let rain: Rain? // 강수량 정보 추가
let dtTEXT: String // 날짜와 시간 정보
enum CodingKeys: String, CodingKey {
case main // JSON 키와 구조체 키의 매핑
case wind
case rain
case dtTEXT = "dt_TEXT" // JSON에서 "dt_txt" 키를 "dtTxt" 변수와 매핑
}
}