본문 바로가기

Swift

함수를 구현하는 순서, 방식 (데이터 더보기)

private func fetchAllPages(for section: Int, completion: @escaping ([AttractionItem]) -> Void) {
        var allItems: [AttractionItem] = []
        var currentPage = 1
        let maxPages = 10
        
        let spotParameters: SpotPrameters
        switch section {
        case 0: spotParameters = .spaCollection
        case 1: spotParameters = .themaCollection
        case 2: spotParameters = .museumCollection
        case 3: spotParameters = .marketCollection
        default: return
        }
        
        func fetchPage() {
            let contentTypeId = spotParameters.contentTypeId
            let cat1 = spotParameters.cat1
            let cat2 = spotParameters.cat2
            let cat3 = spotParameters.cat3
            
            NetworkManager.shared.getAreaBasedList(
                pageNo: String(currentPage),
                contentTypeId: contentTypeId,
                cat1: cat1,
                cat2: cat2,
                cat3: cat3
            ) { result in
                switch result {
                case .success(let response):
                    // items가 배열로 반환된다고 가정하고 바로 추가
                    let items = response.response.body.items.item
                    allItems.append(contentsOf: items)
                    
                    // 다음 페이지로 이동
                    if items.count == 5 && currentPage < maxPages {
                        currentPage += 1
                        fetchPage()
                    } else {
                        completion(allItems)
                    }
                    
                case .failure(let error):
                    print("Error fetching page \(currentPage): \(error.localizedDescription)")
                    completion(allItems)  // 오류가 발생한 경우, 누적된 데이터 반환
                }
            }
        }
        
        fetchPage()
    }

 

 

이 메서드는 특정 섹션에 대한 데이터를 여러 페이지에 걸쳐 가져와서 누적하는 역할을 합니다. 기본적으로, API의 응답을 페이지별로 받아오면서 최대 10페이지까지 데이터를 가져오고, 페이지에서 받아온 데이터를 allItems 배열에 누적한 뒤에 최종 결과를 completion 핸들러로 반환합니다.

 

private func fetchAllPages(for section: Int, completion: @escaping ([AttractionItem]) -> Void) {

 

 

  • 이 메서드는 특정 section에 해당하는 데이터를 받아오고, 완성된 배열을 completion 핸들러를 통해 반환합니다.
  • completion 핸들러의 타입은 [AttractionItem] -> Void로, AttractionItem 배열을 반환합니다
    var allItems: [AttractionItem] = []
    var currentPage = 1
    let maxPages = 10

 

 

 

  • allItems: 모든 페이지의 데이터를 누적해서 저장할 배열입니다.
  • currentPage: 현재 요청할 페이지 번호입니다. 초기 값은 1입니다.
  • maxPages: 최대 가져올 페이지 수를 10으로 제한합니다.
    let spotParameters: SpotPrameters
    switch section {
    case 0: spotParameters = .spaCollection
    case 1: spotParameters = .themaCollection
    case 2: spotParameters = .museumCollection
    case 3: spotParameters = .marketCollection
    default: return
    }

 

 

 

  • spotParameters는 SpotPrameters 타입의 값으로, section에 따라 서로 다른 카테고리 값을 설정합니다. 섹션 번호에 따라 API 호출에 필요한 파라미터가 달라지도록 합니다.
  • 예를 들어, section이 0이면 .spaCollection 파라미터가 설정됩니다.
    func fetchPage() {
        let contentTypeId = spotParameters.contentTypeId
        let cat1 = spotParameters.cat1
        let cat2 = spotParameters.cat2
        let cat3 = spotParameters.cat3

 

 

 

  • fetchPage는 각 페이지를 가져오는 실제 API 호출 함수입니다.
  • spotParameters에서 설정된 contentTypeId, cat1, cat2, cat3 값을 가져옵니다. 이는 SpotPrameters 열거형에서 정의된 카테고리별 매개변수입니다.
        NetworkManager.shared.getAreaBasedList(
            pageNo: String(currentPage),
            contentTypeId: contentTypeId,
            cat1: cat1,
            cat2: cat2,
            cat3: cat3
        ) { [weak self] result in

 

 

 

  • NetworkManager의 getAreaBasedList 메서드를 호출하여, currentPage와 필요한 매개변수를 전달하여 데이터를 가져옵니다.
  • result 클로저를 통해 API 요청의 성공 또는 실패를 처리합니다.
            switch result {
            case .success(let response):
                let items = response.response.body.items.item
                allItems.append(contentsOf: items)

 

 

 

  • result가 성공하면 response에서 items 배열을 가져옵니다.
  • items 배열의 모든 요소를 allItems에 추가하여 데이터를 누적합니다.
                if items.count == 5 && currentPage < maxPages {
                    currentPage += 1
                    fetchPage()
                } else {
                    completion(allItems)
                }

 

 

 

  • items.count == 5 && currentPage < maxPages 조건을 확인합니다:
    • items.count == 5: 페이지가 가득 찬 경우 다음 페이지가 있을 수 있으므로, 다음 페이지를 가져옵니다.
    • currentPage < maxPages: 최대 페이지 제한인 10페이지까지만 가져옵니다.
  • 조건이 만족하면 currentPage를 1 증가시키고, fetchPage()를 다시 호출하여 다음 페이지를 가져옵니다.
  • 조건이 만족하지 않으면 completion(allItems)를 호출하여 현재까지 누적된 allItems를 반환하고, fetch가 끝납니다.
            case .failure(let error):
                print("Error fetching page \(currentPage): \(error.localizedDescription)")
                completion(allItems)
            }

 

  • result가 실패하면 오류 메시지를 출력하고, 누적된 allItems를 반환합니다.

 


위와 같은 함수를 설계할 때는 다음의 순서와 접근 방식으로 작업을 진행하는 것이 좋습니다. 단계별로 필요한 요소를 고려하고, 구현을 구체화하면서 코드를 작성하면 됩니다.

1. 목표 정의 및 요구사항 분석

먼저, 함수의 목표와 기능을 명확히 정의합니다.

  • 목표: 특정 카테고리에 해당하는 데이터를 여러 페이지에 걸쳐 누적해서 가져오고, 조건을 만족할 때까지 데이터를 반복적으로 요청합니다.
  • 제약 조건: 최대 10페이지까지만 데이터를 가져오도록 제한하며, 각 페이지의 아이템을 누적해서 하나의 배열로 반환합니다.

2. 데이터 구조 및 변수 정의

요구사항에 맞는 데이터를 어떻게 저장하고 관리할지 결정합니다.

  • 누적 배열: 페이지별로 받아온 데이터를 계속해서 저장할 allItems 배열을 정의합니다.
  • 페이지 관리 변수: currentPage와 maxPages 변수를 사용해 현재 페이지와 최대 페이지 수를 관리합니다.
  • 카테고리 파라미터: SpotPrameters 열거형을 사용하여 section 번호에 따라 API 호출에 필요한 파라미터를 설정합니다.

3. API 호출 흐름 설계

API 호출을 반복적으로 하며 페이지별 데이터를 누적해야 하는 경우, 재귀적 구조나 반복문을 사용할 수 있습니다.

  • 재귀적 구조 사용: fetchPage()라는 내부 함수를 만들어, 현재 페이지를 API로 호출한 후 조건이 만족하면 다시 fetchPage()를 호출하는 방식으로 다음 페이지를 가져오도록 설계합니다.
  • 조건 설정: 데이터를 계속 가져올지 결정하는 조건을 설정합니다. 예를 들어 items.count == 5로 현재 페이지에 데이터를 가득 채운 경우에만 다음 페이지를 가져오도록 합니다.

4. API 호출 및 클로저 처리

  • 비동기 작업 및 클로저: 비동기 API 호출을 위해 NetworkManager의 메서드를 호출하고, API 응답을 completion 클로저로 전달합니다.
  • 성공과 실패 처리: result 클로저에서 성공 및 실패를 각각 처리합니다.
    • 성공 시: items를 allItems에 추가하고, 조건에 따라 다음 페이지를 요청합니다.
    • 실패 시: 오류를 출력하고 누적된 데이터를 반환하여 에러 상황을 유연하게 처리합니다.

5. 종료 조건 설계

반복적으로 데이터를 가져오되, 적절한 종료 조건을 설정합니다.

  • 페이지 제한: currentPage < maxPages로 페이지 제한을 적용합니다.
  • 데이터 조건: items.count == 5로 페이지가 가득 차 있는 경우에만 다음 페이지를 요청합니다.

6. completion 핸들러로 결과 반환

모든 페이지의 데이터를 누적한 후, completion 핸들러를 통해 결과를 반환합니다.

  • 마지막 반환: 마지막 페이지를 가져왔거나 조건에 따라 데이터 수집을 중단할 때 completion(allItems)를 호출하여 데이터를 반환합니다.

설계 순서 예시

위 단계들을 예시로 정리하면 다음과 같습니다:

  1. 목표 정의 - 여러 페이지의 데이터를 하나의 배열로 누적해서 반환하는 함수 필요.
  2. 데이터 구조 결정 - allItems 배열, currentPage, maxPages 등 필요한 변수를 정의.
  3. API 호출 함수 설계 - 내부에 fetchPage() 함수 생성하여 비동기적 데이터 요청 및 조건 기반 반복 구현.
  4. 조건 정의 - 데이터가 가득 찼을 때 다음 페이지 요청, 최대 페이지 수 제한.
  5. 에러 및 종료 처리 - 실패 시 completion(allItems)를 호출해 누적 데이터를 반환하고 종료.
  6. completion 핸들러로 반환 - 모든 데이터가 누적된 후 completion(allItems) 호출.

설계 팁

  • 단계별로 기능을 쪼개기: 한 번에 모든 기능을 구현하려고 하기보다는, 먼저 데이터 누적 방식부터 구현하고, 조건 반복을 추가하는 식으로 단계별로 구현합니다.
  • 재사용성 고려: 필요에 따라 파라미터 값을 재활용할 수 있도록 SpotPrameters 같은 열거형을 만들어 사용합니다.
  • 종료 조건 명확화: API 호출 반복을 위해 명확한 종료 조건을 설정하는 것이 중요합니다.