Swift tableView Pagination
This is now a little bit easier with the addition of a new protocol in iOS10: UITableViewDataSourcePrefetching
https://developer.apple.com/documentation/uikit/uitableviewdatasourceprefetching
For that you need to have server side change also.
Server will accept
fromIndex
andbatchSize
in theAPI
url as query param.let listUrlString = "http://bla.com/json2.php?listType=" + listType + "&t=" + NSUUID().UUIDString + "&batchSize=" + batchSize + "&fromIndex=" + fromIndex
In the server response, there will be an extra key
totalItems
. This will be used to identify all items are received or not. An array or itemsfromIndex
tobatchSize
number of items.
In the app side
First
loadItem()
will be called withfromIndex = 0
andbatchSize = 20
(for example inviewDidLoad()
orviewWillAppear
). removeAll items fromprivateList
array before callingloadItem()
for the first timeServer returns an array of first 20 items and
totalItems
total number of items in the server.Append the 20 items in
privateList
array and reloadtableView
In
tableView:cellForRowAtIndexPath
method check if the cell is the last cell. And check iftotalItems
(form server) is greater thanprivateList.count
. That means there are more items in the server to loadif indexPath.row == privateList.count - 1 { // last cell if totalItems > privateList.count { // more items to fetch loadItem() // increment `fromIndex` by 20 before server call } }
Question: where is refresh ? will be scrolling ?
Refresh after appending new items in the array when server response received. (step 3)
Scrolling will trigger tableView:cellForRowAtIndexPath
for every cell when user scrolls. Code is checking if it is the last cell and fetch remaining items. (step 4)
Sample project added:
https://github.com/rishi420/TableViewPaging
The good and efficient way to do it is by using scrollviewDelegate
in tableview
Just add UIScrollViewDelegate
in your viewController
In view controller
//For Pagination
var isDataLoading:Bool=false
var pageNo:Int=0
var limit:Int=20
var offset:Int=0 //pageNo*limit
var didEndReached:Bool=false
viewDidLoad(_){
tableview.delegate=self //To enable scrollviewdelegate
}
Override two methods from this delegate
func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {
print("scrollViewWillBeginDragging")
isDataLoading = false
}
func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
print("scrollViewDidEndDecelerating")
}
//Pagination
func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {
print("scrollViewDidEndDragging")
if ((tableView.contentOffset.y + tableView.frame.size.height) >= tableView.contentSize.height)
{
if !isDataLoading{
isDataLoading = true
self.pageNo=self.pageNo+1
self.limit=self.limit+10
self.offset=self.limit * self.pageNo
loadCallLogData(offset: self.offset, limit: self.limit)
}
}
}
SWIFT 3.0 and 4.0
If you're sending the page number in the API request then this is the ideal way for implementing pagination in your app.
- declare the variable current Page with initial Value 0 and a bool to check if any list is being loaded with initial value false
var currentPage : Int = 0
var isLoadingList : Bool = false
- This is the function that gets the list example:
func getListFromServer(_ pageNumber: Int){
self.isLoadingList = false
self.table.reloadData()
}
- This is the function that increments page number and calls the API function
func loadMoreItemsForList(){
currentPage += 1
getListFromServer(currentPage)
}
- this is the method that will be called when the scrollView scrolls
func scrollViewDidScroll(_ scrollView: UIScrollView) {
if (((scrollView.contentOffset.y + scrollView.frame.size.height) > scrollView.contentSize.height ) && !isLoadingList){
self.isLoadingList = true
self.loadMoreItemsForList()
}
}
P.S. the bool isLoadingList role is to prevent the scroll view from getting more lists in one drag to the bottom of the table view.