Search code examples
iosswiftuitableviewdatamodel

How to Load More Data from next page when last item of the page found


I have a data response for more pages and currently it loading page no 1 with 20 records only.

When I call the Api I gave page No as 1 as follows.

 func getMovies()
    {
        API.getNewMovies(page: 1, completion: {movies in
            self.nowPlayingMovies = movies
            self.tableView.reloadData()
        })
    }

But I wanted to make page No as dynamic and load more data according to the page numbers.

I Know How to detect when the last row the data reached. But After reached I want to increment the page no and load more data of next page along with the existing data.

I tried like below.. but I know it's wrong and not fully working.

func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
        // Check if the last row number is the same as the last current data element
        if indexPath.row == self.nowPlayingMovies.count - 1 {
            var pageNum:Int = 1
            pageNum += 1
            print(pageNum)
           // self.loadMore()
        }
    }

 func loadMore()
    {
      print("lastItem Reached")
         // let lastItem = nowPlayingMovies.last!
        //  print("lastItem \(lastItem)")
        // What Should I write here to load more data along with current data 
    }

My Data Model

import Foundation

struct APIResults: Decodable {
    let page: Int
    let numResults: Int
    let numPages: Int
    let movies: [Movie]

    private enum CodingKeys: String, CodingKey {
        case page, numResults = "total_results", numPages = "total_pages", movies  = "results"
    }
}

struct Movie: Decodable  {
    let id:Int!
    let posterPath: String
    var videoPath: String?
    let backdrop: String
    let title: String
    var releaseDate: String
    var rating: Double
    let overview: String

    private enum CodingKeys: String, CodingKey {
        case id, posterPath = "poster_path", videoPath, backdrop = "backdrop_path", title, releaseDate = "release_date", rating = "vote_average", overview
    }
}

I'm using a data model. Please explain me with some clear code snippets.

If you want more codes to explain let me know. I will post required codes. Thank You.


Solution

  • Pass the pageNumber as a param and append the movies to your datasource.

    var lastPageRetrieved: Int
    var nowPlayingMovies: [Movie] = []
    var atTheEnd: Bool = false
    
    func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
        // Check if the last row number is the same as the last current data element
        if indexPath.row == self.nowPlayingMovies.count - 1 {
            // Last item reach, load the next page if we're not at the end
            if !atTheEnd {
                self.loadMore()
            }
        }
    }
    
    func loadMore() {
        // Get the next page number
        var nextPage: Int = 1
        if lastPageRetrieved > 0 {
            nextPage += lastPageRetrieved
        }
    
        // Call the API with the right page number
        getMovies(page: nextPage)
    }
    
    func getMovies(page: Int) {
        API.getNewMovies(page: page, completion: {movies in
    
            guard let movies = movies else {
                // The movies were not loaded, are we at the end?  You can make this even
                //   smarter by checking the number of records in the page and if the records
                //   are less than the max page size, we'll know this is the last page
                self.atTheEnd = true
                return
            }
    
            // Append the new movies to the data source
            self.nowPlayingMovies += movies
    
            // Record the last page you retrieved
            self.lastPageRetrieved = page
    
            // Reload your tableView with the new movies
            self.tableView.reloadData()
        })
    }
    

    You'll need to store which page you last retrieved and set it after you get the page's data. Also, consider error handling when the API fails to return or you've reached the last page.

    Update: I edited the code to be a little more robust.