I'm trying to let users delete a row from a UITableView that's populated using a NSFetchedResultsController but keep getting a fatal error:
Terminating app due to uncaught exception
'NSInternalInconsistencyException', reason: 'Invalid update: invalid
number of rows in section 1. The number of rows contained in an
existing section after the update (7) must be equal to the number of
rows contained in that section before the update (7), 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).'
I'm deleting the core data entry and then deleting the row in the tableView in my code but still get the error above:
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete {
self.feedTable.beginUpdates()
let event = self.fetchedResultsController.object(at: indexPath) as Event
self.managedObjectContext.delete(self.fetchedResultsController.object(at: indexPath))
do {
try self.managedObjectContext.save()
} catch {}
self.feedTable.deleteRows(at: [indexPath], with: .automatic)
self.feedTable.endUpdates()
}
}
Can anybody help understand what I'm doing wrong?
If you use a fetched results controller. Only delete the object with
self.managedObjectContext.delete(self.fetchedResultsController.object(at: indexPath))
Try this solution
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete {
let event = self.fetchedResultsController.object(at: indexPath) as Event
self.managedObjectContext.delete(self.fetchedResultsController.object(at: indexPath))
do {
try self.managedObjectContext.save()
} catch {}
}
}
You don't need beginUpdates and endUpdates
Related
I make a table view on my application, I want to add option that could the user delete the row in tableview.
I'm using this func
h1 is my array string that I put it in tableview.
my error is when I'm try to delete row in func editinstyle
var h1:[String] = ["one","two","three"]
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
h1.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var cell = self.tableView.dequeueReusableCell(withIdentifier: "cell3", for: indexPath as IndexPath) as! TableView1
cell.information.text = h1[indexPath.row]
}
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete {
print("Deleted")
h1.remove(at: indexPath.row) //Remove element from your array
print(h1)
tableView.deleteRows(at: [indexPath], with: .fade)
}
}
when I try to click to Delete it show like this 2020-02-11 20:43:35.803024+0200 TraniersApp[13314:401189] *** 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 (2) must be equal to the number of rows contained in that section before the update (2), 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).'
Does someone know where is the problem?
To define "[indexPath]". It becomes [IndexPath(row: indexPath.row, section: 0)]
tableView.deleteRows(at: [IndexPath(row: indexPath.row, section: 0)], with: .automatic)
or
recall the particular section in the table view also
This will work outside of the function
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath)
Suspect this is a race condition that can be resolved by performing the h1.remove() and tableView.deleteRows() within a transaction (i.e., between tableView.beginUpdates() and tableView.endUpdates()).
tableView.beginUpdates()
h1.remove(at: indexPath.row) //Remove element from your array
tableView.deleteRows(at: [indexPath], with: .fade)
tableView.endUpdates()
Swift 3.0 iOS 10.x
Using this code to try and delete a row in a table...
override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == UITableViewCellEditingStyle.delete {
print("DELETE \(indexPath)")
self.tableView.deleteRows(at: [indexPath], with: UITableViewRowAnimation.automatic)
}
}
This fails with the error message?
2017-05-29 13:36:23.843228+0200[939:576777] *** 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 (9) must be equal to the number of rows contained in that section before the update (9), 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).'
Which sounds fair enough only this is boiler plate code? I am doing little more than clicking on the red button?
Yes, there are 3 rows here... in my code that crashed there were 9.
What have I missed here? Printed out the returned indexPath here and indeed it was wrong, but wait I didn't set it. This method did?
DELETE [0, 3]
You must delete row in your data array before deleting in tableView
override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == UITableViewCellEditingStyle.delete {
print("DELETE \(indexPath)")
yourArray.remove(at: indexPath.row) /* delete in data array */
self.tableView.deleteRows(at: [indexPath], with: UITableViewRowAnimation.automatic)
}
}
Swift 3.0 iOS 10.x
Using this code to try and delete a row in a table...
override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == UITableViewCellEditingStyle.delete {
print("DELETE \(indexPath)")
self.tableView.deleteRows(at: [indexPath], with: UITableViewRowAnimation.automatic)
}
}
This fails with the error message?
2017-05-29 13:36:23.843228+0200[939:576777] *** 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 (9) must be equal to the number of rows contained in that section before the update (9), 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).'
Which sounds fair enough only this is boiler plate code? I am doing little more than clicking on the red button?
Yes, there are 3 rows here... in my code that crashed there were 9.
What have I missed here? Printed out the returned indexPath here and indeed it was wrong, but wait I didn't set it. This method did?
DELETE [0, 3]
You must delete row in your data array before deleting in tableView
override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == UITableViewCellEditingStyle.delete {
print("DELETE \(indexPath)")
yourArray.remove(at: indexPath.row) /* delete in data array */
self.tableView.deleteRows(at: [indexPath], with: UITableViewRowAnimation.automatic)
}
}
I have an array which populates a table view - myPosts.
The first row of the table view is not part of the array.
Each row is its own section (with its own custom footer)
I am trying to perform a delete with the following code:
func tableView(profileTableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {
if (editingStyle == UITableViewCellEditingStyle.Delete) {
myPosts?.removeAtIndex(indexPath.section - 1)
profileTableView.beginUpdates()
let indexSet = NSMutableIndexSet()
indexSet.addIndex(indexPath.section - 1)
profileTableView.deleteSections(indexSet, withRowAnimation: UITableViewRowAnimation.Automatic)
profileTableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: UITableViewRowAnimation.Automatic)
profileTableView.endUpdates()
...
WS Call
...
}
}
And the log is reporting the following:
Invalid update: invalid number of rows in section 0. The number of
rows contained in an
existing section after the update (1) must be equal to the number of rows contained in that
section before the update (1), 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).'
Obviously the issue is related to 0 moved in, 0 moved out but I don't understand why that is? or what the solution would be?
Number of sections in tableView is as follows:
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
if self.myPosts == nil
{
return 1
}
return self.myPosts!.count + 1
}
Updated the answer for Swift 4.2 and made a few additional tweaks:
func tableView(_ tableView: UITableView,
commit editingStyle: UITableViewCell.EditingStyle,
forRowAt indexPath: IndexPath) {
if editingStyle == .delete {
myPosts?.removeAtIndex(indexPath.section - 1)
let indexSet = IndexSet(arrayLiteral: indexPath.section)
profileTableView.deleteSections(indexSet, with: .automatic)
// Perform any follow up actions here
}
}
The use of beginUpdates() and endUpdates() is not necessary, since you are only doing one action that contains animation. If you are doing 2 or more, than it is worth combining them to get a fluid effect.
Also, this makes use of the Swift 3 classes, by doing away with the NSMutableIndexSet() call, which would require a conversion now to work with the deleteSections() call.
So the answer is just removing the line that deletes the rows.
So the code is here to delete:
func tableView(profileTableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {
if (editingStyle == UITableViewCellEditingStyle.Delete) {
myPosts?.removeAtIndex(indexPath.section - 1)
profileTableView.beginUpdates()
let indexSet = NSMutableIndexSet()
indexSet.addIndex(indexPath.section - 1)
profileTableView.deleteSections(indexSet, withRowAnimation: UITableViewRowAnimation.Automatic)
// profileTableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: UITableViewRowAnimation.Automatic)
profileTableView.endUpdates()
...
WS Call
...
}
}
I am trying to delete row from table view and core data the following way:
override func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {
if (editingStyle == UITableViewCellEditingStyle.Delete) {
managedObjectContext?.deleteObject(self.fetchedResultsController.objectAtIndexPath(indexPath) as! NSManagedObject)
managedObjectContext?.save(nil)
self.tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: UITableViewRowAnimation.Fade)
self.tableView.reloadData()
}
}
But on self.tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: UITableViewRowAnimation.Fade) my application crashes with the following error:
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 (7) must be equal to the number of rows contained in that section before the update (7), 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).'
Maybe someone had something like this. Can anyone help me?
After you delete a row, your function numberOfRowsForSection is called again.
So by the time you delete the row, you should also update the value that you return in the aforementioned function.