How to do pagination for a TableView with the MovieDB API Swift?

521 views Asked by At

I'm trying to create an app where the user scrolls to the bottom of the tableview more results are displayed. At present only 20 items are displayed as per the API. The API has a parameter for page which I'm trying to increment by 1 each time the user scrolls to the bottom via this in the ViewController. Endpoint https://api.themoviedb.org/3/movie/popular?api_key=API_KEY&language=en-US&page=1

func scrollViewDidScroll(_ scrollView: UIScrollView) {
        let offsetY = scrollView.contentOffset.y

        if offsetY > (tableView.contentSize.height - 100 - scrollView.frame.size.height){
            viewModel.getMovies() { _ in
                DispatchQueue.main.async {
                    self.tableView.reloadData()
                }
            }
        }

In my ViewModel I have these functions that make the requests

    func incrementCurrentPage() -> Int {
        var number = movieDBService.currentPage
        number += 1
        return number
    }
    func getMoreMovies(completion: @escaping (Result<Void, Error>) -> Void) {
        let page = incrementCurrentPage()

        getMovies(pageNumber: page) { result in
            switch result {
            case .success():
                completion(.success(()))
            case .failure(let error):
                completion(.failure(error))
            }
        }
    }  
func getMovies(pageNumber: Int, completion: @escaping (Result<Void, Error>) -> Void) {

        movieDBService.getPopularMovies(pageNumber: pageNumber) { result in
            switch result {
            case .success(let movie):
                self?.movies = movies.results 
                    completion(.success(()))
            case .failure(let error):
                completion(.failure(error))
            }
        }
    }

In my service class I have a property

 var currentPage: Int = 1

and a function which retrieves the data namely


    func getPopularMovies(pageNumber: Int, completion: @escaping (Result<MovieDBModel, Error>) -> Void) {

        let url = constructMovieEndpoint(pageNumber: pageNumber)

        let task = URLSession.shared.dataTask(with: url) { data, response, error in

            guard let response = response else { return }

            guard let data = data else { completion(.failure(.noData))
                return
            }

            guard error == nil else { return }

            do {
                let decoder = JSONDecoder()
                let movieData = try decoder.decode(MovieDBModel.self, from: data)
                completion(.success(movieData))
            } catch {
                completion(.failure(.decodingError))
            }
        }
        task.resume()
    }

Any help would be appreciated.

1

There are 1 answers

0
Keshu R. On BEST ANSWER

As answered in comments:

You are overriding movies with new data.

self?.movies = movies.results

Instead you should just add/append the new data received so that the previous movie records are preserverd. something like

self?.movies += movies.results

For the tableview scroll:

The lag is coz of the images that you are directly loading from url. You should use SDWebImage for asynchronous image downloading.