UITableView load more when scrolling to bottom like Facebook application
Interview Questions practice on Codemia
Over 8,000 real interview questions from top companies, searchable by company and role.
Introduction
Infinite scrolling lets users browse large datasets without tapping a "next page" button. As the user scrolls near the bottom of a UITableView, the app fetches the next page of results and appends them to the list. This pattern is used in apps like Facebook, Twitter, and Instagram to create a seamless content feed experience.
Detecting the Scroll Position
The core of infinite scrolling is detecting when the user has scrolled close to the bottom of the table view. Since UITableView inherits from UIScrollView, you can use the scrollViewDidScroll delegate method to monitor the current scroll offset.
The threshold of 100 points triggers the load before the user reaches the absolute bottom, creating a smoother experience. Adjust this value based on row height and how far ahead you want to prefetch.
Implementing Pagination Logic
The loadMoreData method checks guard conditions before making a network request. This prevents duplicate fetches and unnecessary calls when all data has been loaded.
The hasMoreData flag is set to false when the server returns fewer items than the requested page size, indicating no more pages exist. The isLoading flag prevents scrollViewDidScroll from triggering multiple simultaneous requests.
Adding a Loading Indicator in the Footer
A spinner in the table footer tells the user that more content is loading. This provides visual feedback and prevents confusion when the user reaches the end of the current content.
Remove the footer view once loading completes by setting tableView.tableFooterView = nil inside the data task completion handler.
Inserting Rows Without Full Reload
Calling reloadData() after every page load causes the table to flash and resets the scroll position in some cases. Using insertRows(at:with:) provides a smoother animation and preserves the current scroll state.
performBatchUpdates wraps the insertion in an animation block. The .automatic animation style lets UIKit choose the most appropriate transition.
Adding Pull-to-Refresh
Pull-to-refresh lets the user reload the feed from the beginning. This complements infinite scrolling by providing a way to see new content that was posted after the initial load.
Inside the loadData completion handler, call tableView.refreshControl?.endRefreshing() to dismiss the spinner after the fresh data has loaded.
Offset-Based vs Cursor-Based Pagination
The examples above use page-based pagination. In production, cursor-based pagination is more reliable because it handles insertions and deletions between pages. Instead of a page number, the API returns a cursor token that points to the next batch.
With cursor pagination, duplicate items are avoided even when new content is added to the feed between page loads.
Common Pitfalls
- Not guarding against duplicate requests: Without the
isLoadingflag,scrollViewDidScrollfires many times per scroll gesture, triggering dozens of simultaneous network requests for the same page. - Calling reloadData on a background thread: UIKit requires all UI updates on the main thread. Calling
reloadDatafrom a network callback withoutDispatchQueue.main.asynccauses crashes or visual glitches. - Forgetting to reset state on pull-to-refresh: If you do not reset
currentPage,hasMoreData, anditemswhen the user pulls to refresh, the next pagination fetch returns the wrong page. - Using a fixed threshold for all devices: A threshold of 100 points works on iPhones but may feel too early or too late on iPads with larger screens. Consider calculating the threshold as a percentage of the frame height.
- Not handling empty or error states: When the network request fails, the loading indicator stays visible indefinitely. Always set
isLoading = falseand remove the footer in both success and error paths.
Summary
- Detect scroll position in
scrollViewDidScrollby comparingcontentOffset.yagainstcontentSize.height - frame.heightminus a threshold. - Use
isLoadingandhasMoreDataflags to prevent duplicate fetches and stop pagination when the server has no more data. - Display a
UIActivityIndicatorViewin the table footer view during loading for clear user feedback. - Use
performBatchUpdateswithinsertRows(at:with:)instead ofreloadData()for smooth row insertion without scroll jumps. - Combine infinite scrolling with
UIRefreshControlfor pull-to-refresh, and prefer cursor-based pagination over page numbers for production feeds.
Related reading
- UITableView not showing first time, only when scrolling a bit
- UITableview reloaddata with animation
- UITableView row animation duration and completion callback
- UITableView, Separator color where to set?
- UITableView set to static cells. Is it possible to hide some of the cells programmatically?
- UITableView viewForHeaderInSection not called during reloadData
- UITableView with fixed section headers
- UITableview with more than One Custom Cells with Swift
.png&w=3840&q=75)
Tackling System Design Interview Problems
A short course that equips you with the skills to approach system design interviews methodically.
Start the free courseTrack what you have practised
A free account saves your progress, solutions and study plan across every problem on Codemia.
Interview Questions practice on Codemia
Over 8,000 real interview questions from top companies, searchable by company and role.