0

I'm trying to use a swipe delete function to remove tableview cells. It works fine, except when I have only 1 cell remaining. If I delete the last cell, I get the titular error message. What's going wrong here? It seems to be an internal logic error, but I'm deleting the item from my array before the row is deleted, so shouldn't the row reflect that? Thanks in advance!

Here's some setup:

private var resultArray: [SavedResult] = []

private var decodedData = [SavedResult]()


@IBOutlet weak var resultsTableView: UITableView!

var resultLabel = "none"

override func viewDidLoad() {
    super.viewDidLoad()
    
    self.resultsTableView.delegate = self
    resultsTableView.dataSource = self
    resultsTableView.rowHeight = 80.0
    loadCellName()
    
}

func loadCellName() {
    
    resultArray = []
    
    
    if let data = try? Data(contentsOf: filePath!) {
     
    let decoder = PropertyListDecoder()
    do {
        decodedData = try decoder.decode([SavedResult].self, from: data)
    } catch {
        print("There was an error loading data: \(error)")
    }
    }
    resultArray = decodedData
    self.resultsTableView.reloadData()
}

and here's all my tableview/data source/swipe stuff:

  extension SavedViewController: UITableViewDataSource {
    
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        
        if resultArray.count == 0 {
            
            return 1
        } else {
        return resultArray.count
        }
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

        let cell = resultsTableView.dequeueReusableCell(withIdentifier: "ResultCell", for: indexPath) as! SwipeTableViewCell
        
        cell.delegate = self
        
        if resultArray.count == 0 {

            cell.textLabel?.text = "No Saved Results Yet."
            cell.textLabel?.attributedText = NSAttributedString(string: (cell.textLabel?.text)!, attributes: [NSAttributedString.Key.font : UIFont(name: "Caveat", size: 30.0)])
            cell.backgroundColor = blueCell
            cell.accessoryType = .none
            cell.isUserInteractionEnabled = false
            return cell
        } else {
            
            cell.textLabel?.text = resultArray[indexPath.row].name
            
            cell.textLabel?.attributedText = NSAttributedString(string: (cell.textLabel?.text)!, attributes: [NSAttributedString.Key.font : UIFont(name: "Caveat", size: 30.0)])
            
            
            switch indexPath.row {
            case 0, 3, 6, 9, 12, 15, 18, 21, 24, 27:
                cell.backgroundColor = blueCell
            case 1, 4, 7, 10, 13, 16, 19, 22, 25:
                cell.backgroundColor = yellowCell
                case 2, 5, 8, 11, 14, 17, 20, 23:
                cell.backgroundColor = purpleCell
            default:
                fatalError("cell background colour setting failed.")
            }
            
            
            return cell
        }
        
    }

}

extension SavedViewController: UITableViewDelegate {
    
    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        
        resultLabel = resultArray[indexPath.row].resultMessage
        resultsTableView.deselectRow(at: indexPath, animated: true)
        self.performSegue(withIdentifier: "savedExamSeg", sender: self)
}
}
   
extension SavedViewController: SwipeTableViewCellDelegate {
    
   
    func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath, for orientation: SwipeActionsOrientation) -> [SwipeAction]? {
        
        guard orientation == .right else { return nil }
        let deleteAction = SwipeAction(style: .destructive, title: "Delete") { action, indexPath in
                
                self.resultArray.remove(at: indexPath.row)

                let encoder = PropertyListEncoder()
                do {
                    
                    let data = try encoder.encode(self.resultArray)
                    try data.write(to: self.filePath!)
                } catch {
                    
                    print("There was an error saving data: \(error)")
                }
            
            }
        
        
        deleteAction.image = UIImage(named: "deleteIcon")
 
        return [deleteAction]
    }
    
    func tableView(_ tableView: UITableView, editActionsOptionsForRowAt indexPath: IndexPath, for orientation: SwipeActionsOrientation) -> SwipeOptions {
        
        var options = SwipeTableOptions()
        options.expansionStyle = .destructive
        return options
    }
vadian
  • 274,689
  • 30
  • 353
  • 361
Jake Jake
  • 9
  • 4

1 Answers1

0

You have to tell the table view to delete the row

self.resultArray.remove(at: indexPath.row)
tableView.deleteRows(at: [indexPath], with: .fade)
vadian
  • 274,689
  • 30
  • 353
  • 361
  • I tried this before (and gave it a go again just now), but it crashes, with the following error: Thread 1: "attempt to delete row 4 from section 0 which only contains 4 rows before the update" . In general, without this line the tableview is actually deleting rows when I swipe. It only fails and crashes when I get to the final row in the tableview – Jake Jake Nov 21 '22 at 17:58
  • When the array is empty you show a *no data* row. I guess this causes the issue. – vadian Nov 21 '22 at 18:02
  • Where would you suggest I fix this? For some reason, 'numberOfRowsInSection' seems only to be called once I delete the final row, not any of the others. And I presume this triggers 'cellForRowAt' again, which then crashes. But if the array being empty is the issue, I thought I would have handled it in my 'if' statement in 'numberOfRowsInSection', which will return 1 row if array count is 0, and works fine when the tableview is first loaded – Jake Jake Nov 21 '22 at 18:09
  • You could show the *no data* information in a header rather than in a cell – vadian Nov 21 '22 at 18:11
  • Yeah I guess, but I suppose then that final row/cell will still be there and visible to the user, while I really need it to be deleted altogether – Jake Jake Nov 21 '22 at 18:18