Book2onNon는 알라딘 도서 API(알라딘 Open API 매뉴얼)를 사용하고 있다.
알라딘 도서 API는 QueryPram으로 Start(검색결과 시작페이지), MaxResults(검색결과 한 페이지당 최대 출력 개수)를 전달할 수 있다.
이는 개발자가 검색 결과를 한번에 다 받을지, 나누어 받을지 결정할 수 있음을 의미한다.
➡️ 검색 결과의 수가 적다면 문제가 되지 않겠지만, 검색 결과가 몇 백 ~ 몇 천 단위이면 앱에서 처리하는데 과부화가 발생할 수 있다고 판단이 되었고, Book2onNon에서는 MaxResults를 10으로 지정하여 한번 검색 요청 시 10개의 데이터만 받아도록 했다.
문제는 "그럼 나머지 검색 결과 값은 어떻게 처리할래?" 였다. 내가 생각한 가장 좋은 방법은 무한 스크롤을 이용하는 것이었다. 스크롤링 이벤트를 감지하면 QueryPram으로 Start(검색결과 시작페이지)에 다음 페이지 값을 인자를 넘겨 검색 결과를 요청하고 검색 결과를TableView에 Bind하는 것이다.
무한 스크롤 설계
1. 스크롤 위치 감지
➡️ 처음엔 UIScrollViewDelegate 프로토콜을 확장하여 scrollViewDidScroll 메소드를 이용하는 방법을 사용했다.
본 프로젝트에서는 RxSwift와 RxCocoa를 사용하고 있기에, 최대한 Rx를 활용하기 위해서 찾아보니 RxCocoa에서 제공하는 rx.didScroll이 있음을 알게 되었고, 이로 구현하였다.
didScroll은 사용자가 Scroll 이벤트를 실행할 때 발생한다.
이벤트가 계속 실행되면 안되므로, throttle 메소드를 이용해서 이벤트를 제어한다.
dueTime은 throttle을 적용할 시간 간격이고, latest는 Bool 값으로 false로 설정하면 throttle이 첫 번째로 발생한 이벤트를 기준으로 시간 간격을 적용한다. scheduler는 throttle 연산자에서 사용할 스케줄러를 지정한다. 나는 throttle를 2초 간격으로 적용하도록 하였다.
만약 throttle을 적용하지 않는다면 위 처럼 스크롤링 한번에 데이터를 계속 요청하게 될 것이다.
다음으로 스크롤의 위치를 감지하여 하단에 닿았는지를 Bool 값으로 mapping하여 return하도록 구현하였다.
마지막으로 viewModel의 isSearchResultTableViewisNearBottomEdge에 bind하였다.
2. 데이터 요청
가장 처음에 생각한 방법은, 기존 검색 결과에 scan연산자를 이용하는 방법이었다.
하지만 아래와 같은 이유로 scan연산자가 아니라 기존 검색 결과에 새로운 값을 추가하는 방식으로 구현했다.
✅ 간단함 : scan 연산자를 사용하기 위해서는 복잡한 로직을 구성해야한다. 하지만 새로운 값을 추가하는 방법은 간단하고 직관적으로 구현할 수 있다.
✅ 메모리 문제 : scan 연산자를 사용하면 매번 새로운 결과를 생성해야 하기 때문에 메모리 사용량이 늘어날 수 있다. 기존 검색 결과에 새로운 값을 추가하는 방법은 결과를 생성하는 것이 아닌 결과를 업데이트하는 방식으로 동작하기에 scan을 사용하는 것보다 메모리 관리 측면에서 유리하다.
✅ filter : filter 연산자를 이용해서 true일 때만 작동하도록 했다.
✅ withLatestFrom : DropDownItem과 검색 텍스트를 combineLatest 연산자를 이용해서 새로운 Observable을 Create하고 withLatestFrom 연산자를 이용해서 스크롤링 이벤트가 발생하면 작동하도록 했다.
✅ flatMap : combine한 Observable을 이용하여 (Int,Book) 튜플을 갖는 Observable을 return하도록 구현하였다. nextPage에 현재 페이지 + 1 값을 저장하고, tryGetBook 메소드를 이용해서 검색을 요청한다. 요청한 값을 (nextPage, 결과 값) 튜플로 매핑하여 Observable<(Int, Book)>으로 return한다.
✅ 해당 Return 값을 구독하여 current 페이지에 다음 페이지를 저장하고, outputSearchResultItem에 accept한다.
3. 데이터 바인딩
새로운 output 변수를 생성한 것이 아니기 때문에, 기존에 사용하던 resultSearchItem을 이용해서 바인딩 한다.
✏️ resultSearchItem은 Driver이기 때문에 메인 스레드에서 작동하고 TableView에 데이터를 바인딩하면 데이터가 변경될 때 자동으로 TableView가 업데이트 되므로 reload()를 별도로 호출하지 않아도 된다.
결과
'ToyProject - Book2OnNon (모바일 서재)' 카테고리의 다른 글
[Book2OnNon/회고] Book2OnNon 개발을 마무리 하며 (0) | 2024.05.16 |
---|---|
[Book2onNon] 하위 View에 상위 ViewController의 ViewModel 주입하기 (0) | 2024.03.26 |