Pagination이란 뭐고, 왜 필요할까?
Pagination이란 한 페이지에 보여줄 수 있는 데이터의 양은 한계가 있는데, 데이터가 너무 많기에 단계(페이지)를 쪼개서 필요한 만큼만 보여주는 것이다.
리소스를 분할하거나, 서버 데이터를 다룰 때 주로 사용한다.
Pagination 방식
- Offset-based Pagination: 몇 번째 페이지에 몇 개의 데이터를 보여줄지 설정하는 방식
- 보통 이 방법이 일반적이다. 데이터 갱신이 실시간으로 이루어지지 않을 때, 사용되는 방식이다. (ex. 블로그, 영화 정보 등)
- 페이지를 이동할 때, 데이터를 미리 불러올 수 있다는 점이 장점이자 단점이다.
- 데이터를 미리 불러옴으로써 UX적인 측면에서는 좋지만, 데이터를 미리 불러오기 때문에 리소스를 낭비할 수 있고 실시간으로 데이터가 갱신되지 않는다는 단점이 있다.
- Cursor-based Pagination
- 클라이언트가 가지고 있는 마지막 데이터를 기준으로 다음 데이터를 불러오는 방식
- 데이터가 실시간으로 갱신되는 경우에 사용한다. (ex. 채팅, 실시간 게임 등)
-> 방식에 따라 URL 링크가 달라진다.
Pagination 구현하는 3가지 방법
- UITableView의
willDisplayCell
메서드를 사용하는 방법willDisplayCell
메서드는 셀이 화면에 보여지기 직전에 호출되는 메서드이다.- 단점은 셀이 안보이는 데도 호출되기 때문에, 불필요한 데이터를 불러올 수 있다는 점이다.
- 또한, 마지막 스크롤 시점을 잡는 게 어렵다는 점이 있다.
UITableViewDataSourcePrefetching
프로토콜을 사용하는 방법- 다음 URL에 대한 데이터를 미리 불러올 수 있다.
- 보편적으로 많이 사용되는 방법이다.
- 서버 통신과 같은 비동기 상황에서 쉽게 구현이 가능하다
- 용량이 큰 이미지를 테이블뷰셀에 보여주려고 하는 등의 상황에서 유용하다.
UIScrollViewDelegate
프로토콜 - 스크롤뷰의 Offset 활용하는 방법- scrollview contentsize의 offset을 활용하여 구현하는 방법이다.
- 실질적인 화면 높이랑 offset이 유사해지는 간격을 계산하여 다음 데이터를 요청한다.
- 2번과 같이 많이 사용되는 방식 중 하나이다.
이 중에서 2번 방법인 UITableViewDataSourcePrefetching
프로토콜을 사용하는 구현 방식을 자세히 적어보려고 한다.
Pagination 구현하기
1. UITableView에 UITableViewDataSourcePrefetching
프로토콜 채택, 프로토콜 프로퍼티를 테이블뷰에 할당
extension VideoViewController: UITableViewDelegate, UITableViewDataSource, UITableViewDataSourcePrefetching {
}
해당 코드와 같이 첫 번째로 UITableViewDataSourcePrefetching
프로토콜을 표현하고자 하는 뷰컨트롤러에 채택한다.
override func viewDidLoad() {
super.viewDidLoad()
tableView.prefetchDataSource = self
}
두 번째로 UITableViewDataSourcePrefetching
프로토콜의 프로퍼티를 테이블뷰에 할당하는 작업이 필요하다.
(UIViewController에서 TableView를 구현할 때 UITableViewDelegate
, UITableViewDataSource를
채택하고, 프로토콜 프로퍼티를 테이블뷰에 할당하는 것과 유사하다.)
2. prefetchRowsAt
메서드에서 데이터를 불러오는 작업을 구현
- 셀이 화면에 보이기 직전에 (
cellForRowAt
메서드가 호출되기 직전에) 호출되는 메서드로, 필요한 리소스를 미리 다운 받을 수 있다. - Row의 갯수(videoList의 개수)와 indexPath.row의 위치를 비교하여 스크롤 시점을 확인해서 네트워크 요청을 시도하면 된다.
func tableView(_ tableView: UITableView, prefetchRowsAt indexPaths: [IndexPath]) {
for indexPath in indexPaths {
if videoList.count - 1 == indexPath.row && page < 15 && !isEnd {
page += 1
callRequest(query: searchBar.text!, page: page)
}
}
}
여기서 코드를 살펴보면, videoList.count - 1 == indexPath.row
조건문을 통해 마지막 셀이 화면에 보여질 때, 다음 데이터를 요청하도록 구현했다.
그리고, page < 15 && !isEnd
조건문은 페이지에 대한 조건인데, 이러한 조건은 불러오고자 하는 API의 특성에 따라 달라질 수 있다.
여기서는 KakaoSearchVideo API를 사용했는데, 해당 API는 15페이지까지만 요청이 가능하기에, page < 15
조건문을 추가했다.
그리고 isEnd
는 API의 마지막 페이지인지 아닌지를 판단하는 Bool 값이다.
3. cancelPrefetchingForRowsAt
메서드에서 데이터 요청을 취소하는 작업을 구현
func tableView(_ tableView: UITableView, cancelPrefetchingForRowsAt indexPaths: [IndexPath]) {
// 데이터 요청을 취소하는 작업
}
- 사용자가 스크롤을 아주 빠르게 했을 때, 중간에 지나가는 셀에 대한 데이터 처리가 필요 없을 때,
cancelPrefetchingForRowsAt
메서드가 호출해 데이터 요청을 취소할 수 있다. cancelPrefetchingForRowsAt
메서드는prefetchRowsAt
메서드보다 먼저 실행된다.- 직접 취소하는 기능을 구현해 주는 게 필요함.
이번에는 prefetching을 사용하여 pagination을 구현해 보았는데, 다음번에 스크롤뷰의 offset을 활용한 구현도 해봐야겠다고 생각했다..
테이블뷰가 스크롤뷰를 상속받아서 생기는 특성들에 대해 공부해 볼 필요성을 느낌..! 좀 더 열심히 살자ㅠ
Reference