[Swift/Ios]NetworkManager 리뷰 및 복습

이진규·2024년 8월 19일
  1. NetworkManager 클래스 - 싱글톤 패턴
 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 생성자를 만듭니다.

}

  • 싱글톤 패턴을 사용하여 네트워크 매니저의 인스턴스를 하나만 생성하도록 설계되었습니다. 이를 통해 앱 전반에서 동일한 인스턴스를 공유하여 네트워크 요청을 관리할 수 있습니다.
  • static let shared = NetworkManager()는 싱글톤 인스턴스를 생성하는 코드입니다. 외부에서 NetworkManager.shared를 호출해 사용할 수 있습니다.
  • private init()은 외부에서 이 클래스의 새로운 인스턴스를 생성하지 못하게 막아줍니다. 이로 인해 자원의 낭비를 방지할 수 있습니다.
  1. fetchData 메서드 - 제네릭을 사용한 공통 네트워크 요청 메서드
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() // 요청 시작
}
  • fetchData 메서드는 제네릭을 사용하여 다양한 타입의 데이터를 처리할 수 있습니다. T는 Decodable 프로토콜을 따르는 타입이어야 하며, 이로 인해 JSON 데이터를 Swift 객체로 쉽게 디코딩할 수 있습니다.
  • URLSession을 사용하여 네트워크 요청을 수행하며, 요청이 완료되면 data, response, error 값을 통해 응답을 처리합니다.
  • HTTPURLResponse의 statusCode를 통해 응답이 성공적인지(200~299 범위 내) 확인한 후, 성공적일 경우 JSONDecoder()를 사용해 데이터를 디코딩합니다.
  • 디코딩이 성공하면 completion 핸들러를 통해 데이터를 반환하고, 실패하면 nil을 반환합 니다.
  1. fetchCurrentWeatherData 메서드 - 현재 날씨 데이터 요청
	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) // 이미지 로드 실패 시 데이터만 반환
                }
            }
        }
    }
}
  • fetchCurrentWeatherData 메서드는 주어진 위도와 경도를 기반으로 현재 날씨 데이터를 불러오는 메서드입니다.
  • URLComponents를 사용하여 API 요청에 필요한 URL을 동적으로 구성합니다. 이를 통해 위도, 경도, API 키, 온도 단위를 요청 URL에 쿼리 매개변수로 추가합니다.
  • 생성된 URL을 fetchData 메서드에 전달하여 네트워크 요청을 보냅니다.
  • 요청이 성공하면 날씨 데이터와 날씨 아이콘을 로드합니다. 날씨 아이콘은 비동기로 로드되 며,로드가 완료되면 completion 핸들러를 통해 이미지와 날씨 데이터를 반환합니다.
  1. fetchForecastData 메서드 - 5일 날씨 예보 데이터 요청
	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) // 제네릭을 활용해 다양한 타입의 데이터 처리가 가능
}
  • fetchForecastData 메서드는 주어진 위도와 경도를 기반으로 5일 간의 날씨 예보 데이터 를 불러옵니다.
  • 이 메서드는 fetchCurrentWeatherData와 유사하게 URLComponents를 사용해 URL을 구성하고, fetchData를 호출하여 데이터를 가져옵니다.
  • 제네릭을 활용한 처리: fetchData 메서드가 제네릭으로 구현되어 있기 때문에, 이 메서드 에서도 예보 데이터를 간단하게 처리할 수 있습니다.
  1. 모델 구조체 정의
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" 변수와 매핑
    }
}
  • 모델 구조체는 OpenWeatherMap API의 JSON 데이터를 Swift 객체로 변환하기 위해 사 용됩니다. 각 필드에 맞는 데이터 타입을 지정하며, 서버로부터 받은 데이터를 쉽게 처리할 수 있게 해줍니다.
  • Codable 프로토콜을 준수하여 JSON 데이터를 디코딩(혹은 인코딩)할 수 있습니다.
  • CodingKeys는 JSON 키와 Swift 구조체의 변수명을 매핑하는 역할을 합니다.
profile
열공중~

0개의 댓글