iOS/Swift

enum을 통해 api 함수 관리해보기

밤새는 탐험가89 2024. 8. 31. 06:43

 각 카테고리에 대한 contentId를 효율적으로 관리하기 위해서 enum을 사용하면 좋습니다. enum을 사용하면 각 카테고리에 해당하는 contentId를 쉽게 정의하고 관리할 수 있습니다.

 

 여기서 enum을 정의하고, switch문을 활용하여 contentId를 매핑한 후 NetworkManager의 메서드에서 해당 contentId를 사용하여 데이터를 요청할 수 있습니다.

 

1. ContentCategory Enum 정의

먼저, 각 카테고리에 대응하는 contentId를 enum으로 정의합니다.

enum ContentCategory: String {
    case attractions = "12"
    case facilities = "14"
    case events = "15"
    case course = "25"
    case leisureActivity = "28"
    
    var contentId: String {
        return self.rawValue
    }
}

 

여기서 ContentCategory의 rawValue로 contentId를 설정했습니다. 이제 각 카테고리별로 contentId를 쉽게 얻을 수 있습니다.

 

2. didSelectItemAt 메서드 수정

didSelectItemAt 메서드에서 ContentCategory를 사용하여 각 카테고리 선택 시에 해당하는 contentId를 쉽게 가져올 수 있습니다.

func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
    if collectionView == categoryCollectionView.getcategoryCollectionView() {
        selectedIndex = indexPath.item
        collectionView.reloadData() // 선택 상태 업데이트

        var selectedCategory: ContentCategory?
        
        switch selectedIndex {
        case 0:
            selectedCategory = .attractions
        case 1:
            selectedCategory = .facilities
        case 2:
            selectedCategory = .events
        case 3:
            selectedCategory = .course
        case 4:
            selectedCategory = .leisureActivity
        default:
            break
        }
        
        if let category = selectedCategory {
            NetworkManager.shared.getAttractionData(contentId: category.contentId) { result in
                // 데이터를 받아온 후 UI 업데이트 등을 처리
                switch result {
                case .success(let items):
                    // items를 사용하여 UI 업데이트 처리
                    print(items)
                case .failure(let error):
                    // 에러 처리
                    print(error.localizedDescription)
                }
            }
        }
    } else if collectionView == hotplacesCollectionView.getHotPlacesCollectionView() {
        // HotPlaces 컬렉션 뷰 아이템 선택 시 처리
        print("Selected hot place at index \(indexPath.item)")
    }
}

 

 

3. NetworkManager 메서드 수정

NetworkManager의 getAttractionData 메서드는 그대로 유지하되, contentId를 enum에서 받아온 값으로 전달할 수 있게 구성합니다.

class NetworkManager {
    
    static let shared = NetworkManager()
    
    func getAttractionData(contentId: String, completion: @escaping (Result<[Item], Error>) -> Void) {
        guard let url = URL(string: "https://apis.data.go.kr/B551011/KorService1/searchKeyword1?serviceKey=개인키&numOfRows=1000000&pageNo=1&MobileOS=ETC&MobileApp=AppTest&_type=json&listYN=Y&arrange=A&keyword=%EA%B0%95%EC%9B%90&contentTypeId=\(contentId)") else  { return }
        
        let task = URLSession.shared.dataTask(with: URLRequest(url: url)) { data, _, error in
            guard let data = data , error == nil else {
                completion(.failure(error!))
                return
            }
        
            do {
                let results = try JSONDecoder().decode(AttractionResponse.self, from: data)
                completion(.success(results.response.body.items.item))
            } catch {
                completion(.failure(error))
            }
        }
        
        task.resume()
    }
}

 

 

⭐️ enum ContentCategory에서 var contentId를 정의한 이유?

enum ContentCategory: String {
    case attractions = "12"
    case facilities = "14"
    case events = "15"
    case course = "25"
    case leisureActivity = "28"
    
    var contentId: String {
        return self.rawValue
    }
}

 

 

contentId를 사용하는 이유

  1. 가독성 향상:
    • contentId라는 이름은 해당 프로퍼티가 무엇을 나타내는지 명확하게 전달합니다. 반면, rawValue는 enum의 기본 제공 프로퍼티로, 어떤 값인지 즉시 이해하기 어려울 수 있습니다.
    • 예를 들어, category.contentId는 그 자체로 "카테고리의 콘텐츠 ID"라는 의미를 분명히 전달하지만, category.rawValue는 단순히 "원시 값"이라는 의미로 해석될 수 있습니다.
  2. 의도 명확화:
    • contentId를 통해 이 값이 콘텐츠를 식별하는 ID임을 명확히 나타낼 수 있습니다. 이는 코드의 의도를 분명히 하고, 다른 개발자들이 코드를 이해하기 쉽게 만듭니다.
  3. 유지보수 용이성:
    • 만약 나중에 contentId를 계산 방식이나 다른 값으로 변경해야 할 경우, contentId 프로퍼티 내부에서만 변경하면 되므로 코드 전체를 수정할 필요가 없습니다.
    • 예를 들어, 현재는 단순히 rawValue를 반환하지만, 추후 로직이 추가될 경우에도 contentId 프로퍼티 내에서만 수정하면 됩니다.

 

⭐️ selectedCategory에는 원시값을 넣어야하니까 에를 들면 .events.contentId 이렇게 적어야하는거 아냐?

 

selectedCategory에 ContentCategory의 원시값(rawValue)을 사용하려면, selectedCategory에 직접 ContentCategory 열거형의 인스턴스를 할당하는 대신, 그 원시값을 contentId 프로퍼티를 통해 설정하는 것이 맞습니다.

 

수정된 코드

var selectedCategory: String?

switch selectedIndex {
case 0:
    selectedCategory = ContentCategory.attractions.contentId
case 1:
    selectedCategory = ContentCategory.facilities.contentId
case 2:
    selectedCategory = ContentCategory.events.contentId
case 3:
    selectedCategory = ContentCategory.course.contentId
case 4:
    selectedCategory = ContentCategory.leisureActivity.contentId
default:
    break
}

 

설명

  • selectedCategory 변수는 String? 타입으로 선언되었습니다. 이 변수에 ContentCategory의 원시값(contentId)을 할당하기 위해서는 selectedCategory = .events.contentId처럼 contentId 프로퍼티를 통해 접근해야 합니다.
  • ContentCategory의 각 경우에 대해 .attractions.contentId, .facilities.contentId 등을 사용함으로써 해당 카테고리의 ID를 selectedCategory 변수에 할당할 수 있습니다.

대안: ContentCategory? 타입 사용

만약 selectedCategory를 String이 아닌 ContentCategory? 타입으로 선언하고, 이후에 contentId를 사용할 계획이라면 아래처럼 할 수 있습니다:

var selectedCategory: ContentCategory?

switch selectedIndex {
case 0:
    selectedCategory = .attractions
case 1:
    selectedCategory = .facilities
case 2:
    selectedCategory = .events
case 3:
    selectedCategory = .course
case 4:
    selectedCategory = .leisureActivity
default:
    break
}

// 이후 필요할 때
if let category = selectedCategory {
    let contentId = category.contentId
    // contentId를 사용해 네트워크 요청을 수행하는 등의 작업
}

 

이 접근 방식에서는 selectedCategory를 ContentCategory 타입으로 유지하면서, 필요할 때 contentId를 얻어 사용할 수 있습니다. 이 방법은 타입 안전성을 유지하면서도 각 카테고리를 쉽게 구분할 수 있게 합니다.