본문 바로가기

Project/MovieClip

🚜 서치 기능 개선 (MVVM + Combine)

📌 수정 전 SearchViewModel

class SearchViewModel: ObservableObject {
    
    ...
    
    func loadMoreMovies() {
        guard canLoadMoreMovies else { return }
        
        Task {
            do {
                moviePage += 1
                let moreMovies = try await NetworkManager.shared.searchMovie(with: currentQuery, page: moviePage)
                DispatchQueue.main.async {
                    let newMovies = moreMovies.results.prefix(5)
                    self.movies.append(contentsOf: newMovies)
                    
                    // ✅ 추가할 데이터가 더 이상 없으면 더보기 비활성화
                    self.canLoadMoreMovies = newMovies.count == 5
                }
            } catch {
                print("❌ 추가 영화 로드 실패: \(error.localizedDescription)")
            }
        }
    }
    ...
    
}

 

더보기 버튼 동작 개선: "검색 결과 전체보기"로 변경 & 불필요한 페이지 요청 방지

🔹 기존 문제:

  • 무조건 1페이지 더 불러오는 방식 → 불필요한 API 호출 발생
  • 현재 검색 결과가 10개 미만이라면 다음 페이지를 불러올 필요가 없음
  • "더보기" 대신 "검색 결과 전체보기" 버튼으로 변경

 

 

 

✅ 1. 개선된 방식

1️⃣ 검색 결과의 첫 페이지에서 가져온 전체 개수를 기준으로 "더보기" 버튼 동작 결정
2️⃣ 현재 데이터 개수가 첫 페이지의 결과 개수보다 작을 때만 "더보기" 버튼 활성화
3️⃣ "더보기" 버튼 텍스트를 "검색 결과 전체보기"로 변경
4️⃣ 마지막 페이지까지 로드되면 버튼을 자동으로 숨김

 

✅ 2. SearchViewModel 수정 (불필요한 로드 방지)

import Combine

class SearchViewModel: ObservableObject {
    
    @Published var movies: [MediaResult] = []
    @Published var tvShows: [MediaResult] = []
    @Published var people: [PersonResult] = []
    
    @Published var canLoadMoreMovies = false
    @Published var canLoadMoreTVShows = false
    @Published var canLoadMorePeople = false
    
    private let searchService = SearchService()
    private var cancellables = Set<AnyCancellable>()
    
    private var currentQuery = ""
    private var moviePage = 1
    private var tvPage = 1
    private var peoplePage = 1
    
    private var totalMoviesCount = 0
    private var totalTVShowsCount = 0
    private var totalPeopleCount = 0
    
    // MARK: - 검색 실행
    func search(query: String) {
        currentQuery = query
        resetState()
        
        Task {
            do {
                let results = try await searchService.searchAll(with: query, page: 1)
                DispatchQueue.main.async {
                    self.movies = results.movies.results
                    self.tvShows = results.tvShows.results
                    self.people = results.people.results

                    self.totalMoviesCount = results.movies.totalResults
                    self.totalTVShowsCount = results.tvShows.totalResults
                    self.totalPeopleCount = results.people.totalResults
                    
                    self.updateLoadMoreStatus()
                }
            } catch {
                print("❌ 검색 요청 실패: \(error.localizedDescription)")
            }
        }
    }
    
    // MARK: - 더보기 실행 (불필요한 요청 방지)
    func loadMore(for type: MediaType) {
        switch type {
        case .movies:
            guard movies.count < totalMoviesCount else { return }
            fetchMoreMovies()
        case .tvShows:
            guard tvShows.count < totalTVShowsCount else { return }
            fetchMoreTVShows()
        case .people:
            guard people.count < totalPeopleCount else { return }
            fetchMorePeople()
        }
    }
    
    // MARK: - API 호출하여 추가 데이터 가져오기
    private func fetchMoreMovies() {
        moviePage += 1
        Task {
            do {
                let moreMovies = try await searchService.searchMovie(with: currentQuery, page: moviePage)
                DispatchQueue.main.async {
                    self.movies.append(contentsOf: moreMovies.results)
                    self.updateLoadMoreStatus()
                }
            } catch {
                print("❌ 추가 영화 로드 실패: \(error.localizedDescription)")
            }
        }
    }

    private func fetchMoreTVShows() {
        tvPage += 1
        Task {
            do {
                let moreTVShows = try await searchService.searchTV(with: currentQuery, page: tvPage)
                DispatchQueue.main.async {
                    self.tvShows.append(contentsOf: moreTVShows.results)
                    self.updateLoadMoreStatus()
                }
            } catch {
                print("❌ 추가 TV 로드 실패: \(error.localizedDescription)")
            }
        }
    }

    private func fetchMorePeople() {
        peoplePage += 1
        Task {
            do {
                let morePeople = try await searchService.searchPerson(with: currentQuery, page: peoplePage)
                DispatchQueue.main.async {
                    self.people.append(contentsOf: morePeople.results)
                    self.updateLoadMoreStatus()
                }
            } catch {
                print("❌ 추가 인물 로드 실패: \(error.localizedDescription)")
            }
        }
    }
    
    // MARK: - "더보기" 버튼 활성화 여부 업데이트
    private func updateLoadMoreStatus() {
        canLoadMoreMovies = movies.count < totalMoviesCount
        canLoadMoreTVShows = tvShows.count < totalTVShowsCount
        canLoadMorePeople = people.count < totalPeopleCount
    }
    
    // MARK: - 상태 초기화
    private func resetState() {
        moviePage = 1
        tvPage = 1
        peoplePage = 1

        totalMoviesCount = 0
        totalTVShowsCount = 0
        totalPeopleCount = 0

        canLoadMoreMovies = false
        canLoadMoreTVShows = false
        canLoadMorePeople = false

        movies.removeAll()
        tvShows.removeAll()
        people.removeAll()
    }
}