0
votes

I've implemented the following deleting mechanism: on delete action tableView deletes selected rows and if section does not have any rows it will be deleted.

My mechanism looks like this:

guard let selectedRows = self.tableView.indexPathsForSelectedRows,
      let indexPath = self.tableView.indexPathForSelectedRow else { return }
                
self.tableView.beginUpdates()
self.dataSource[indexPath.section].rows.remove(at: indexPath.item)
                
if self.dataSource[indexPath.section].rows.isEmpty {
    self.dataSource.remove(at: indexPath.item)
    self.tableView.deleteSections(IndexSet(arrayLiteral: indexPath.section), with: .fade)
}
                
self.tableView.deleteRows(at: selectedRows, with: .fade)
self.tableView.endUpdates()

My dataSource object:

struct DataSource {
    var section:String
    var rows:[Row]
}

struct Row {
    var data:String
}

The problem is when I select more than one row and try to delete selected rows I've got a crush with following message:

Invalid update: invalid number of rows in section 0. The number of rows contained in an existing section after the update (5) must be equal to the number of rows contained in that section before the update (6), plus or minus the number of rows inserted or deleted from that section (0 inserted, 2 deleted) and plus or minus the number of rows moved into or out of that section (0 moved in, 0 moved out).'

While I delete by one row my mechanism works fine, as expected. Even deletes an empty section. Any thoughts, where am I wrong? Thanks a lot.

1
As far as I see, self.dataSource[indexPath.section].rows.remove(at: indexPath.item) removes only one array item.Roman Ryzhiy
It is up to you how to do it. indexPath is the array of selected indices. developer.apple.com/documentation/foundation/indexpathRoman Ryzhiy
Don't use self. as much if not needed. It unnecessarily reduces readability and adds additional length without much gain.Deitsch
You check to see if the datasource is empty for the section. Then you delete the section from the tableview. But you don't confirm that the tableview's section is empty. If tableView.deleteSections is called on a non-empty section, I suspect that it is deleting the row, then the section. Then your code steps down and calls tableView.deleteRows. This could be causing the duplicate deletion.DPrice
@Bugrym I see. Just an idea: move the code to a function and just call the function like self.doStuff(). This may also improve overall readabilityDeitsch

1 Answers

0
votes

Solution: just add inverted indexPath array. let invertedIndexPathes = selectedRows.sorted(by: >)

Fixed mechanism:

guard let selectedRows = self.tableView.indexPathsForSelectedRows,
       let indexPath = self.tableView.indexPathForSelectedRow else { return }

let invertedIndexPathes = selectedRows.sorted(by: >)
self.tableView.beginUpdates()
            
for itemIndexPath in invertedIndexPathes {
    self.dataSource[itemIndexPath.section].rows.remove(at: itemIndexPath.row)
    self.tableView.deleteRows(at: [itemIndexPath], with: .fade)
    self.tableView.reloadData()
}
            
if self.dataSource[indexPath.section].rows.isEmpty {
    self.dataSource.remove(at: indexPath.item)
    self.tableView.deleteSections(IndexSet(arrayLiteral: indexPath.section), with: .fade)
}
            
self.tableView.endUpdates()