49

I have a table of names and I am making a swipe and delete function for them which removes them from a names variable which is an array.

I selected the functions which most closely resembled the tutorial inside xcode and filled them out, but my app crashes randomly when I click the delete button. Here is my code for the delete button:

func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]? {
    let deleteAction = UITableViewRowAction(style: .destructive, title: "Delete") { (rowAction: UITableViewRowAction, indexPath: IndexPath) -> Void in
        print("Deleted")
        self.catNames.remove(at: indexPath.row)
        self.tableView.deleteRows(at: [indexPath], with: UITableViewRowAnimation.automatic)
        self.tableView.reloadData()
    }
}

I'm new to coding and learning swift, I am following a tutorial for swift 2 and working with swift 3 so there are a few issues I have when following along, this being one I'm properly stuck on.

pkamb
  • 33,281
  • 23
  • 160
  • 191
infernouk
  • 1,137
  • 4
  • 13
  • 21
  • 2
    Simply remove the call to `reloadData`. – rmaddy Oct 20 '16 at 14:01
  • 1
    FYI - whenever you post a question about a crash, you must include relevant details about the crash including the exact line causing the crash and the complete error message. – rmaddy Oct 20 '16 at 14:03
  • Removing the `reloadData` call will not fix the issue. Look at the answers below. – Phil Hudson Oct 20 '16 at 14:04
  • @PhilHudson There is no need to call `reloadData` when the OP is already correctly calling `deleteRows`. And until the OP posts details about the crash, there is no way to know for sure what the complete solution may be. – rmaddy Oct 20 '16 at 14:13
  • @maddy just by looking at the code, you can see where the bug is. Sure it should have provided the crash log but what you're suggesting is best practice not the actual root cause. – Phil Hudson Oct 20 '16 at 14:15

9 Answers9

132

Works for Swift 3 and Swift 4

Use the UITableViewDataSource tableView(:commit:forRowAt:) method, see also this answer here:

func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
  if editingStyle == .delete {
    print("Deleted")

    self.catNames.remove(at: indexPath.row)
    self.tableView.deleteRows(at: [indexPath], with: .automatic)
  }
}
ronatory
  • 7,156
  • 4
  • 29
  • 49
28

First you need to add this function

func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
    return true 
}

then your function is ok but no need of tableview reload data just call tableview.beingUpdates and tableview.endUpdates

func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
    if editingStyle == .delete {
       print("Deleted")
       self.catNames.remove(at: indexPath.row)
       self.tableView.beginUpdates()
       self.tableView.deleteRows(at: [indexPath], with: .automatic)
       self.tableView.endUpdates() 
    }
}
Luca Davanzo
  • 21,000
  • 15
  • 120
  • 146
ivan123
  • 317
  • 2
  • 7
9

In Swift 4 Try This

func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
        return true
    }
    func tableView(_ tableView: UITableView, commit editingStyle:   UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
        if (editingStyle == .delete) {
            arrStudentName.remove(at: indexPath.row)
            tableView.beginUpdates()
            tableView.deleteRows(at: [indexPath], with: .middle)
            tableView.endUpdates()
        }
    }
Berlin
  • 2,115
  • 2
  • 16
  • 28
  • 1
    It is always a good idea to mention what protocol these methods are part of. In this case it is UITableViewDataSource for both methods. – rommex Jan 31 '19 at 19:08
3
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {

    if editingStyle == .delete {

        self.animals.remove(at: indexPath.row)

        self.dataDisplayTbleView.reloadData()
    }

}
Arya McCarthy
  • 8,554
  • 4
  • 34
  • 56
suri
  • 57
  • 1
  • 5
2

**

for swift 3

**

  func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
      if editingStyle == .delete {
        print("Deleted")

        self.catNames.remove(at: indexPath.row)
        self.tableView.deleteRows(at: [indexPath], with: .automatic)
      }
    }
Govind Wadhwa
  • 904
  • 8
  • 16
0

My answer for you

func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool
{
     return true
}

func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath)
{
    if editingStyle == .delete
    {
        array.remove(at: indexPath.row)
        tblDltRow.reloadData()
    }
}

You need to refresh the table

user3182143
  • 9,459
  • 3
  • 32
  • 39
  • 4
    According to @rmaddy from another answer reloading for just a removed element is a bad practice. instead of reloading It should be something like self.tableView.deleteRows(at: [indexPath], with: .automatic). You really dont know how the cell works or is defined. Imagine a long list with a complex custom Cell maybe with images, a reload could force downloading or trigger – le0diaz Apr 04 '17 at 17:09
  • @le0diaz, Actually today I got the issue I have the tableview in which we are showing the user lists and there there is delete button in every cell. If I delete the first row, it will delete the first row from table view but if I delete the 10 row after deleting the first row. Delete button will have wrong index and it is deleting the row from tableview. – Mandeep Singh Aug 01 '18 at 08:35
  • Hi Possible can I ask question related to moveRow ? –  Feb 26 '20 at 10:54
  • @le0diaz same issue here. How did you fix it? I am calling delete function from the cell using delegates. – Yessen Yermukhanbet Jul 05 '21 at 16:33
0

You don't have to reload the tableView.

Before you use tableView.deleteRows(at: [IndexPath], with: UITableView.RowAnimation) you must substrate the number of rows you want delete in numberOfRowsInSection

    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {

return //Your current number of rows - The number of rows to delete

    }

Normally the number of rows is the number of Items from an array (yourArray.count), that means you can delete the items from this array before you delete the cells and you get the same result.

-1
    self.tableView.beginUpdates()
    self.tableView.deleteRows(at: [ IndexPath(row: index, section: section) ], with: .fade)
    self.remove_object_from_model()
    self.tableView.endUpdates()
Lee Irvine
  • 3,057
  • 1
  • 15
  • 12
-1

For Swift 5

func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
      if editingStyle == .delete {
        print("Deleted")

        self.catNames.remove(at: indexPath.row)
        self.tableView.deleteRows(at: [indexPath], with: .automatic)
      }
    }