Automatic UITableView Paging
Episode
#309
|
15 minutes
| published on
November 2, 2017
| Uses Xcode-9.1-beta1, swift-4
Free Video
UITableView can support scrolling through many rows of data, however fetching large amounts of remote data can slow down your app, use up too much memory, and bog down your web server. This is all wasteful if users aren‘t ever going to scroll down that far. In this episode you‘ll learn how to perform automatic UITableView pagination using an easy technique.
Want more? Subscribers can view all 485 episodes. New episodes are released regularly.
This episode is a refresh of Episode 8.
Setting Up
private var beers: [Beer] = []
private var currentPage = 1
private var shouldShowLoadingCell = false
override func viewDidLoad() {
// ...
refreshControl = UIRefreshControl()
refreshControl?.addTarget(self, action: #selector(refreshBeers), for: .valueChanged)
refreshControl?.beginRefreshing()
loadBeers()
}
Loading the Data
private func loadBeers(refresh: Bool = false) {
print("Fetching page \(currentPage)")
breweryDBClient.fetchBeers(page: currentPage, styleId: 3) { page in
DispatchQueue.main.async {
if refresh {
self.beers = page.data
} else {
for beer in page.data {
if !self.beers.contains(beer) {
self.beers.append(beer)
}
}
}
self.shouldShowLoadingCell = page.currentPage < page.numberOfPages
self.refreshControl?.endRefreshing()
self.tableView.reloadData()
}
}
}
Fetching the next page
private func fetchNextPage() {
currentPage += 1
loadBeers()
}
Showing the Loading Cell
If we need to show a loading cell we need to add 1 to the cell count:
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
let count = beers.count
return shouldShowLoadingCell ? count + 1 : count
}
Then return a cell for the loading index path:
private func isLoadingIndexPath(_ indexPath: IndexPath) -> Bool {
guard shouldShowLoadingCell else { return false }
return indexPath.row == self.beers.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if isLoadingIndexPath(indexPath) {
return LoadingCell(style: .default, reuseIdentifier: "loading")
} else {
//...
}
}
Then we need to trigger the next page load when the cell is displayed...
override func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
guard isLoadingIndexPath(indexPath) else { return }
fetchNextPage()
}
Refreshing the Data
@objc
private func refreshBeers() {
currentPage = 1
loadBeers(refresh: true)
}