Update UITableView when user scrolls to end (Swift)

A very common way of displaying a list of items in an iOS app is using a UITableView which gets its data, typically, from an array that holds the items to be displayed in each cell. If the items to be displayed are fetched with an API call to a web server then it is probably not to a good idea to get hundreds of items from the server in one call and then set up the tableview to display. Even if you do display lots of items, at one point your user will scroll down to the end and (unless you don’t have anything else to show) you will need to make another request to the server to get more data.

It is quite normal to display a limited set of items initially and then fetch more data if the user reaches the end of current set. This behaviour is seen in many apps including both Facebook and Twitter and is a seamless experience such that the user often doesn’t notice when more items are fetched and added to the tableview as he or she scrolls down. So how exactly does this work?

It is actually very straightforward. UITableView conforms to UIScrollViewDelegate so all you need to do is implement the scrollViewDidScroll: delegate where you’d detect the current scroll position in the UITableView. If the user reaches the point where you are running out of items to be displayed you will make a request to get more data. Just make sure that when you do make a request or are updating data, set a flag of some kind so that any further scroll doesn’t result in repeated calls.

Here’s the code snippet I have used.

let threshold = 100.0 // threshold from bottom of tableView
var isLoadingMore = false // flag

func scrollViewDidScroll(scrollView: UIScrollView) {
let contentOffset = scrollView.contentOffset.y
let maximumOffset = scrollView.contentSize.height - scrollView.frame.size.height;

if !isLoadingMore && (maximumOffset - contentOffset <= threshold) {
// Get more data - API call
self.isLoadingMore = true

// Update UI
dispatch_async(dispatch_get_main_queue()) {
tableView.reloadData()
self.isLoadingMore = false
}
}
}

5 Comments

Leave a Comment