본문 바로가기

iOS (스파르타)

무한스크롤~!

무한 스크롤이라,,,, 

 

무한 스크롤이란,,!

기본적으로 사용자가 리스트를 스크롤할 때, 현재 로드된 데이터의 끝에 도달하면 추가 데이터를 요청하여 계속해서 콘텐츠를 로드하는 방식!

 

1. 기본 아이디어

페이지네이션: 데이터를 일정한 단위로 나누어 서버나 로컬 데이터베이스에서 데이터를 요청하는 방식. 예를들어 한번에 20개의 항복만 가져오도록 설정하고, 스크롤이 끝에 도달할 때마다 다음 20개의 항목을 가져온다.

스크롤 감지: 사용자가 스크롤할 때, 현재 스크롤 위치가 리스트의 끝부분에 가까워질 때 새로운 데이터를 요청해야 한다.

 

2. 단계별 구현 방법

1) 데이터 관리

currentPage: 현재 몇 번째 페이지의 데이터를 가져왔는지 추적한다.

isLoading: 데이터가 로드 중인지를 나타낸다. 중복 요청을 방지하기 위해 필요하다.

hasMoreData: 더 이상 로드할 데이터가 없는 경우, 추가 요청을 막기 위해 사용된다.

2) 스크롤 감지

UIScrollViewDelegate 프로토콜을 채택하여 scrollViewDidScroll 메서드를 구현한다.

이 메서드에서 스크롤의 위치를 확인하여 리스트의 끝에 도달했을 때 추가 데이터를 요청한다.

3) 데이터 요청

scrollViewDidScroll 에서 데이터의 끝에 도달했다고 판단되면, 다음 페이지의 데이터를 요청한다.

요청이 완료되면 데이터를 기존 배열에 추가하고, UICollectionView를 업데이트한다.

 

3.구체적인 구현 방법

1) 스크롤 위치를 감지하기 위한 코드: scrollViewDidScroll 메서드에서 스크롤 위치를 감지하고, 데이터의 끝에 가까워질 때 다음 페이지의 데이터를 요청한다.

func scrollViewDidScroll(_ scrollView: UIScrollView) {
    let contentOffsetY = scrollView.contentOffset.y
    let contentHeight = scrollView.contentSize.height
    let frameHeight = scrollView.frame.size.height
    
    // 스크롤 위치가 콘텐츠의 끝에 가까워지면 데이터를 추가로 요청합니다.
    if contentOffsetY > contentHeight - frameHeight * 2 {
        // 데이터 로드 중이 아니고, 더 로드할 데이터가 있다면
        if !isLoading && hasMoreData {
            fetchNextPage()
        }
    }
}

2) 데이터를 요청하는 코드: fetchNextPage 메서드에서 다음 페이지의 데이터를 요청하고, 데이터를 받아오면 컬렉션뷰를 업데이트한다.

func fetchNextPage() {
    guard !isLoading else { return }
    isLoading = true
    
    apiService.fetchPokemonList(page: currentPage, limit: limit) { [weak self] result in
        guard let self = self else { return }
        self.isLoading = false
        
        switch result {
        case .success(let pokemonList):
            self.pokemonList.append(contentsOf: pokemonList.results)
            self.currentPage += 1
            self.collectionView.reloadData()
            
            // 만약 더 이상 가져올 데이터가 없다면
            if pokemonList.results.isEmpty {
                self.hasMoreData = false
            }
            
        case .failure(let error):
            print("Failed to fetch Pokémon list: \(error)")
        }
    }
}

 

4. 중요한 고려 사항

중복 요청 방지: isLoading 플래그를 사용하여 동일한 데이터에 중복 요청을 방지한다.

데이터가 없을 경우 처리: hasMoreData 플래그를 사용하여 더 이상 가져올 데이터가 없는 경우 추가 요청을 막는다.

에러 처리: 데이터 로드가 실패했을 때 적절한 에러 처리를 추가한다.

 

음 일단 지티피가 알려준건 이런것이고 블로그들도 찾아보았다!

 

ViewModel 코드(데이터 정의)

통신하는 부분을 보고 totalPage, currentPage, isLoading 변수 선언해준다.

데이터 통신이 끝나면 테이블 뷰(찾아본 블로그에서는 테이블뷰 난 컬렉션 뷰 하지만 머 같잖아?) 데이터에 기존 데이터를 포함해서 appendData를 해준다. 또한 통신이 시작하기 전에 isLoading 값을 true로 변경해준다. 그리고 통신이 끝난 시점에 isLoading을 false값으로 변경해준다. 통신하는 부분은 코드마다 다를 수 있지만 핵심 변수들은 

totalPage: 전체 페이지 수 (서버에서 받은 값)

currentPage: 현재 로드된 페이지 값

isLoading: 현재 통신 중인지 확인하는 Boolean 값

 

 

 

 

자,, 그럼 이걸 어떻게 내 코드에 써먹느냐!

 

일단 MainViewModel에 데이터관리를 추가해야겠쥐,,?

 

하아 이해가 잘 ! 안가는데

했더니 이미지들이 버벅버벅~ 혼란스러워라~

이거 넷플릭스 클론코딩에서 셀 리유즈하는거 했던거같아서 코드 찾아봤다지,,