리팩토링 전 코드
class NetworkManager {
static let shared = NetworkManager()
func getCommonData(contentId: String, completion: @escaping (Result<[Item], Error>) -> Void) {
guard let url = URL(string: "\(Constants.base_URL)/areaBasedList1?serviceKey=jlK%2B0ig7iLAbdOuTJsnkp6n0RdeEMtGKsw53jEMbKm3PcB7NFTSeUrnXixogiuvNtHQXeqxgV88buRZvTjG73w%3D%3D&numOfRows=10&pageNo=1&MobileOS=ETC&MobileApp=AppTest&_type=json&listYN=Y&arrange=O&contentTypeId=\(contentId)") else { return }
let task = URLSession.shared.dataTask(with: URLRequest(url: url)) { data, _, error in
guard let data = data, error == nil else { return }
do {
let results = try JSONDecoder().decode(AttractionResponse.self, from: data)
completion(.success(results.response.body.items.item))
} catch {
completion(.failure(error))
}
}
task.resume()
}
}
리팩토링 후 코드
class NetworkManager {
static let shared = NetworkManager()
func getCommonData(contentId: String, completion: @escaping (Result<[Item], Error>) -> Void) {
var components = URLComponents(string: "\(Constants.base_URL)/areaBasedList1")
// 쿼리 아이템 설정
components?.queryItems = [
URLQueryItem(name: "serviceKey", value: "jlK%2B0ig7iLAbdOuTJsnkp6n0RdeEMtGKsw53jEMbKm3PcB7NFTSeUrnXixogiuvNtHQXeqxgV88buRZvTjG73w%3D%3D"),
URLQueryItem(name: "numOfRows", value: "10"),
URLQueryItem(name: "pageNo", value: "1"),
URLQueryItem(name: "MobileOS", value: "ETC"),
URLQueryItem(name: "MobileApp", value: "AppTest"),
URLQueryItem(name: "_type", value: "json"),
URLQueryItem(name: "listYN", value: "Y"),
URLQueryItem(name: "arrange", value: "O"),
URLQueryItem(name: "contentTypeId", value: contentId)
]
// URL 생성
guard let url = components?.url else { return }
let task = URLSession.shared.dataTask(with: URLRequest(url: url)) { data, _, error in
guard let data = data, error == nil else { return }
do {
let results = try JSONDecoder().decode(AttractionResponse.self, from: data)
completion(.success(results.response.body.items.item))
} catch {
completion(.failure(error))
}
}
task.resume()
}
}
주요 변경 사항
- URLComponents 사용: URLComponents를 사용하여 URL을 생성합니다. 이렇게 하면 URL을 쉽게 구성하고 쿼리 파라미터를 추가할 수 있습니다.
- URLQueryItem 사용: URLQueryItem을 사용하여 각 쿼리 파라미터를 설정합니다. 이는 URL 인코딩 문제를 방지하고 코드의 가독성을 높입니다.
- components?.url: URLComponents에서 URL을 안전하게 생성합니다. guard let을 사용하여 URL이 유효하지 않은 경우 메서드가 조기에 종료되도록 했습니다.
이점
- 가독성: 쿼리 파라미터가 명확하게 분리되어 가독성이 향상됩니다.
- 안전성: 잘못된 URL 구성을 방지합니다. 예를 들어, URLComponents는 URL 인코딩을 자동으로 처리하므로 하드코딩된 URL과 비교할 때 더 안전합니다.
- 유지보수: 나중에 쿼리 파라미터를 추가하거나 수정해야 할 때 코드 변경이 쉽습니다.
⭐️ 문제 발생 ⭐️
serviceKey의 퍼센트 인코딩 문제가 발생했습니다.
인코딩 되면서 기존의 serviceKey와 다르게 나오는데 이를 해결하고자 필요한 부분을 수동으로 수정하여 클래스를 작성했습니다.
// MARK: - Network Manager
class NetworkManager {
static let shared = NetworkManager()
func getCommonData(contentId: String, completion: @escaping (Result<[Item], Error>) -> Void) {
var components = URLComponents(string: "\(Constants.base_URL)/areaBasedList1")
// 쿼리 아이템 설정
components?.queryItems = [
URLQueryItem(name: "serviceKey", value: Constants.api_key),
URLQueryItem(name: "numOfRows", value: "10"),
URLQueryItem(name: "pageNo", value: "1"),
URLQueryItem(name: "MobileOS", value: "ETC"),
URLQueryItem(name: "MobileApp", value: "AppTest"),
URLQueryItem(name: "_type", value: "json"),
URLQueryItem(name: "listYN", value: "Y"),
URLQueryItem(name: "arrange", value: "O"),
URLQueryItem(name: "contentTypeId", value: contentId)
]
// 퍼센트 인코딩 후 "+"를 "%2B"로 대체
if let encodedQuery = components?.percentEncodedQuery?.replacingOccurrences(of: "%25", with: "%") {
components?.percentEncodedQuery = encodedQuery
}
// URL 생성
guard let url = components?.url else { return }
print(url)
let task = URLSession.shared.dataTask(with: URLRequest(url: url)) { data, _, error in
guard let data = data, error == nil else { return }
do {
let results = try JSONDecoder().decode(AttractionResponse.self, from: data)
completion(.success(results.response.body.items.item))
} catch {
completion(.failure(error))
}
}
task.resume()
}
}
'iOS > UIKIT' 카테고리의 다른 글
탭바 색상 설정 (0) | 2024.09.23 |
---|---|
CollectionView 특정 셀만 업데이트하기 (0) | 2024.09.13 |
minimumInteritemSpacing과 minimumLineSpacing 설정 및 위치 (0) | 2024.09.03 |
커스텀 탭바 내에 있는 아이콘 위치 조절하는 방법 (0) | 2024.09.01 |
DispatchQueue.main.async의 사용 위치와 방식에 따른 차이 (0) | 2024.08.31 |