2
votes

im trying to remove a cell from a TableViewController. Each time i swipe and press the delete button a crash occur.

This is the crash log:

Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Invalid update: invalid number of rows in section 0. The number of rows contained in an existing section after the update (10) must be equal to the number of rows contained in that section before the update (10), plus or minus the number of rows inserted or deleted from that section (0 inserted, 1 deleted) and plus or minus the number of rows moved into or out of that section (0 moved in, 0 moved out).'

and this is my UITableView functions.

override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return 10
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    let myCell = tableView.dequeueReusableCellWithIdentifier(cellID, forIndexPath: indexPath) as! PredefinedServicesCell

    //Cell configuration.
    myCell.selectionStyle = .None
    myCell.containerView.layer.borderColor = UIColor(hex: 0x3399CC).CGColor
    myCell.containerView.layer.borderWidth = 1
    myCell.containerView.layer.cornerRadius = 10
    myCell.containerView.clipsToBounds = true
    myCell.servicePrice.text = "\(indexPath.row)"
    myCell.serviceCurrency.text = "KWD"
    myCell.serviceTitle.text = "Building iOS Application"
    myCell.serviceDescription.text = "This is a service description This is a service description This is a service description This is a service description This is a service description This is a service description This is a service description This is a service description This is a service description"
    return myCell
}
override func tableView(tableView: UITableView, canEditRowAtIndexPath indexPath: NSIndexPath) -> Bool {
    return true
}
override func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {

    if editingStyle == .Delete {
        tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: .Fade)
    }

}

what might the reason be?

8

8 Answers

3
votes

Please dynamically add your numberOfRowsInSection. It's not static.

use array insted of return 10. and remove objec when you delete in editing style.

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

override func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {

    if editingStyle == .Delete {
        tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: .Fade)

// remove object from array here

    }

}

reason behind error: in your case

firs your no of table cell count is 10. When you are delete cell your cell is deleted but count is 10. It's worng otherwise decrease your count to 9.

1
votes

Keep a record of number of deleted cells and delete the same amount from array(used to populate table view) as well.

0
votes

Once you remove the rows from the tableview, you must have to update your numberOfRowsInSection value also. That's why you are getting crash.

let rows=10
    override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return rows
    }
    override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        let myCell = tableView.dequeueReusableCellWithIdentifier(cellID, forIndexPath: indexPath) as! PredefinedServicesCell

        //Cell configuration.
        myCell.selectionStyle = .None
        myCell.containerView.layer.borderColor = UIColor(hex: 0x3399CC).CGColor
        myCell.containerView.layer.borderWidth = 1
        myCell.containerView.layer.cornerRadius = 10
        myCell.containerView.clipsToBounds = true
        myCell.servicePrice.text = "\(indexPath.row)"
        myCell.serviceCurrency.text = "KWD"
        myCell.serviceTitle.text = "Building iOS Application"
        myCell.serviceDescription.text = "This is a service description This is a service description This is a service description This is a service description This is a service description This is a service description This is a service description This is a service description This is a service description"
        return myCell
    }
    override func tableView(tableView: UITableView, canEditRowAtIndexPath indexPath: NSIndexPath) -> Bool {
        return true
    }
    override func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {

        if editingStyle == .Delete {
            tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: .Fade)
            rows-=1
        }

    }
0
votes

Following the crash log, you should update number of rows after editing

    override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return 10
}
0
votes

You cannot return the number of cell as 10, after deleting the cell. It should be less the number of cell before deletion.

0
votes

You have to update your data source to match the number of row/section of your tableview, and use beginUpdate & endUpdate to update your table view display. Like so:

override func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {

    if editingStyle == .Delete {
        tableView.beginUpdate() //optional
        tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: .Fade)
        //TODO ... add your code to update data source here

        tableView.endUpdate() //optional
    }

}
0
votes

You cannot declare a static value to your numberOfRowsInSection and then change it (10 - 1) by removing a row with deleteRowsAtIndexPaths, numberOfRowsInSection remain 10 and your rows become 9 so you have this kind of issue, make these changes to have a dynamic value:

var totalRows: Int = 10

override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return self.totalRows
}

override func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {

    if editingStyle == .Delete {
        if self.totalRows > 0 { // This limit your deletion to avoid a crash
            tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: .Fade)
            self.totalRows -= 1
        }
    }
}

Usually It's better to handle a datasource array to maintain your informations to show in each cell, so think to use an array to do it so you can use it's count property and remove it's element when you delete a cell.

0
votes

Your numberOfRowsInSection should be dynamic not static. So, remove data in the dynamic array with yourdataName.remove(at:indexPath.row)

Example;

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

func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
                if editingStyle == UITableViewCellEditingStyle.delete {
                    yourdataName.remove(at:indexPath.row)
                    tableView.deleteRows(at: [indexPath], with: UITableViewRowAnimation.automatic)
                }
            }