Search code examples
swiftscrolltableviewuisegmentedcontrol

UITableView - Index out of range when segment selected while scrolling


I am getting "Index out of range" in cellForRowAt when segmentedControl index is changed while scrolling the tableView.

@IBAction func segmentedControlAction(_ sender: AnyObject!) {
        if(segmentedControl.selectedSegmentIndex == 0) {
            self.data?.removeAll()
            loadA()
        }
        else if(segmentedControl.selectedSegmentIndex == 1){
            self.data?.removeAll()
            loadB()
        }
    }

 override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

        let cell = tableView.dequeueReusableCell(withIdentifier: "Cell") as! CustomCell

        cell.data = self.data?[indexPath.row] ---> Error here
        return cell
}

LoadA and LoadB are similar functions

func loadA(){
        API.sharedInstance.loadA(start, callback:  { response in
            if let data = response["data"].arrayValue as [JSON]?{
                self.data = data
                DispatchQueue.main.async {
                    self.tableView?.reloadData()
                }
            }
        })
    }

Solution

  • You first remove all the data but don't reload the table. Then you call an async method that later updates the data in the background and finally gets around to reloading the table view on the main queue.

    You need to only update the data model immediately prior to reloading the table view.

    @IBAction func segmentedControlAction(_ sender: AnyObject!) {
        if(segmentedControl.selectedSegmentIndex == 0) {
            loadA()
        }
        else if(segmentedControl.selectedSegmentIndex == 1){
            loadB()
        }
    }
    
    func loadA(){
        API.sharedInstance.loadA(start, callback:  { response in
            if let data = response["data"].arrayValue as [JSON]?{
                DispatchQueue.main.async {
                    self.data = data
                    self.tableView?.reloadData()
                }
            }
        })
    }