Search code examples
swiftuitableviewtableviewreloaddata

Scroll to load data. Swift. UITableView


my code has some problems of loading data by scroll table to a certain row, but I couldn't find out why.

Basically, I want the table to load next 10 elements when scroll to total elements - 5. For example, I want the table initially load 10 elements. Then, when it hits the fifth element, it loads 11-20 elements.

My problem is when I initially load the table, it only loads the first 5 elements but I can see there are some spaces between 6-10, then I scroll the table to the fifth element, it loads the next 10 elements (6 - 15).

let rowPerPage = 10

func refreshResults(){
    // append data from server //
    self.resultsTitleArray.append(...)

    if self.resultsTitleArray.count != 0 {
        let minCount = min(rowPerPage, self.productImageArray.count) - 1
        self.currentResultsTitleArray += self.resultsTitleArray[0...minCount]
    }

    self.resultsTable.reloadData()
}

func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int{
    return currentResultsTitleArray.count
}

func tableView(tableView: UITableView, willDisplayCell cell: UITableViewCell, forRowAtIndexPath indexPath: NSIndexPath) {
    let diff = rowPerPage - 5
    let currentDiff = currentResultsTitleArray.count - 1 - indexPath.row
    if currentResultsTitleArray.count != resultsTitleArray.count && diff == currentDiff {
        let minCount = min(resultsTitleArray.count, currentResultsTitleArray.count + rowPerPage as Int) - 1
        let next = self.currentResultsTitleArray.count
        self.currentResultsTitleArray += self.resultsTitleArray[next...minCount]
        resultsTable.reloadData()
    }
}

Solution

  • Personally I'd change this if statement slightly.. What you're looking to do is load 10 cells when you're 5 away from the bottom only.. but it's slightly dangerous as it could easily load multiple times.

    You need an external var to show the highest successful load you've done so far and check

    if indexPath.row == currentResultsTitleArray.count - 6 && indexPath.row > self.highestIndexFetchedOn should be the trigger, then on a successful fetch, just before reload data, set self.highestIndexFetchedOn to the new indexPath.row

    It's not clear what rowPerPage does but I'm guessing it's 10 and also the minCount logic looks right, but I'd print that out to make sure you're getting what you expect.

    if indexPath.row == currentResultsTitleArray.count - 4 && indexPath.row > self.highestIndexFetchedOn {
    
        let minCount = min(resultsTitleArray.count, currentResultsTitleArray.count + rowPerPage as Int) - 1
        let next = self.currentResultsTitleArray.count
    
        print("Count:",minCount)
    
        self.currentResultsTitleArray += self.resultsTitleArray[next...minCount]
    
        // etc...
    
        self.highestIndexFetchedOn = indexPath.row
        tableView.reloadData()
    }
    

    I'm not sure about the data structure here with all these arrays housing the different data either... I think one array of dictionaries that have all the values in would be better and simplify what we're looking at.. but I can't say 100% without seeing the rest of the class..