Getting the following error when trying to delete a row from a tableview hooked to a fetched results controller:
* Assertion failure in -[UITableView _endCellAnimationsWithContext:], /SourceCache/UIKit_Sim/UIKit-1914.84/UITableView.m:1037
2012-07-12 13:11:19.921 Chef[28843:12203] * 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 (20) must be equal to the number of rows contained in that section before the update (20), 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).'
My code is below.
// Override to support editing the table view.
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
if (editingStyle == UITableViewCellEditingStyleDelete) {
// Delete the record from the DB
RecipeCategory *objectToBeDeleted = [self.fetchedResultsController objectAtIndexPath:indexPath];
[self.context deleteObject:objectToBeDeleted];
// Delete the row from the data source
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
}
else if (editingStyle == UITableViewCellEditingStyleInsert) {
// Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view
}
}
Using a fetch request count, and the method - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section, I have tried logging the number of DB records, and the number of rows in the table before and after the line [self.context deleteObject:objectToBeDeleted];, and they both decrease from 20 to 19.
Please help!
Edit: PS the error occurs at the deleteRowsAtIndexPath method.
It turns out that the line of code below was surplus to requirements. I guess the NSFetchedResultsController handles that as well. I also had to implement the delegate methods for NSFetchedResultsController.
// Delete the row from the data source
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
Related
I am using PFQueryTableViewController with Local Datastore. I want to enable user to delete a object from the table with this code:
// Override to support editing the table view.
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
if (editingStyle == UITableViewCellEditingStyleDelete) {
// Delete the row from the data source
PFObject * object = [self.objects objectAtIndex: indexPath.row];
[object deleteInBackgroundWithBlock: ^ (BOOL succeeded, NSError * error) {
[self loadObjects];
}];
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
}
else if (editingStyle == UITableViewCellEditingStyleInsert) {
// Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view
}
}
I get this
*** 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).'
I think, this is a comment use in a PFQueryTableViewController but I can´t find the solution.
Thanks a lot.
When you delete objects from an array, your changing the structure of your UITableView
Lets say you start off with 100 objects in an array called objectsArray.
numberOfRowsInSection = return objectsArray.count (i.e, 100)
cellsForRowAtIndexPath = 100 cells, or however many that will be reused to show all 100 objects
Now you just deleted some rows from the UITableView here : [tableView deleteRowsAtIndexPaths:....]
So lets say you deleted 3 rows from objectsArray, that means you deleted the tangible rows from the UITableView so the UITableView thinks numberOfRows.. = 100 - 3. But it doesn't, because you haven't updated your array to subtract those 3 objects that you just deleted.
So you are actually reloading the tableView [self loadObjects] before those tangible 3 rows are deleted, or maybe after in your case because the inBackground part. So in other words, your reloading objectsArray again before you are trying to animate the rows out that you deleted from the tableView. This can't happen fast enough, especially since you put it in an asynchronous callback, you probably shouldn't do that for performance sake. So in short, you need to update your array after you delete the rows so numberOfRowsInSection will always reflect the correct number of objects
If your data is sensitive and you need to wait to see if the callback returns a successful deleteInBackground then you should also update your tableView there, because you never know when that method will actually finish:
..deleteInBackgroundWithBlock:^(BOOL succeeded, NSError *error) {
if (succeeded) {
//get main thread
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
[self loadObjects];
} else {
//error in deleting them
}
}
I have a UITableViewController set up that displays my managedObjects properly when it's loaded, however when I go to delete a cell my app crashes. This is what the console has to say:
2015-05-03 09:55:20.125 MyApp[9461:663817] *** 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 (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).'
When I reboot the app and go to my TVC, the object that I deleted the last time is deleted.
I have sections set up in my NSFetchedResultsController that is instantiated when viewDidLoad is called. I suspect I have a small issue, but I'm not sure where to go to add the missing line(s?).
I enable swipe to delete in viewDidLoad with this line:
// Enable swipe to delete
self.tableView.allowsMultipleSelectionDuringEditing = NO;
Here's my commitEditingStyle:
// Override to support editing the table view.
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
if (editingStyle == UITableViewCellEditingStyleDelete) {
// Delete selected NSManagedObject from managedObjectContext
NSManagedObject *objectToDelete = [self.fetchedResultsController objectAtIndexPath:indexPath];
[self.managedObjectContext deleteObject:objectToDelete];
[self.managedObjectContext save:nil];
// Delete the row from the data source
[tableView beginUpdates];
[tableView deleteRowsAtIndexPaths:#[indexPath] withRowAnimation:UITableViewRowAnimationFade];
[tableView endUpdates];
} else if (editingStyle == UITableViewCellEditingStyleInsert) {
// Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view
}
}
Thank you for reading. If you have any ideas, I welcome them.
The error message is saying that number of row returns from numberOfRowInSection is not matching with current number of item in table..
when you use fetchedResultsController numberOfRowsInSection should look something like this.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [[self.fetchedResultsController fetchedObjects] count];
}
and fetchedResultsController delegate didChangeObject: is then called automatically which calls the deleteRowAtIndexPaths: inside.. so you don't need to call the deleteRowAtIndexPaths: just call deleteObject, otherwise it deletes twice.
I added the following code in my iOS app to delete table cell from UITableViewController, but I get an error about the deletion.
-(void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath{
if(editingStyle == UITableViewCellEditingStyleDelete){
[self.toDoItems removeObjectAtIndex:indexPath.row];
NSArray *indexPaths = #[indexPath];
[self.tableView deleteRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationAutomatic];
}
}
Update:
toDoItems is just an NSArray, and I have tried the following code but is still not working:
-(void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath{
if(editingStyle == UITableViewCellEditingStyleDelete){
NSArray *indexPaths = #[indexPath];
[self.tableView deleteRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationAutomatic];
[self.toDoItems removeObjectAtIndex:indexPath.row];
}
}
the error message is here:
'NSInternalInconsistencyException', reason: 'Invalid update: invalid number of rows in section 1. The number of rows contained in an existing section after the update (1003) must be equal to the number of rows contained in that section before the update (1004), plus or minus the number of rows inserted or deleted from that section (0 inserted, 0 deleted) and plus or minus the number of rows moved into or out of that section (0 moved in, 0 moved out).'
Xcode 6.2 iOS6
I have already tried Deleting table cell causes crash
The problem is that you are deleting the wrong object from your data model:
[self.toDoItems removeObjectAtIndex:indexPath.row];
That's too simple-minded. You have multiple sections in this table. You need a data model that distinguishes these sections, and you need to delete the correct row from the correct section in your data model before deleting the corresponding row from the table. You cannot do that by looking at indexPath.row alone; you need to structure your data model so as to take account of indexPath.section as well.
I'm trying to delete nicely the cells of mu UITableView :
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
if (editingStyle == UITableViewCellEditingStyleDelete) {
[self deleteModelForIndexPath:indexPath];
[mainTableView beginUpdates];
[mainTableView deleteRowsAtIndexPaths:indexPath withRowAnimation:UITableViewRowAnimationTop];
[mainTableView endUpdates];
}
}
This throws the following exception :
*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Invalid update: invalid number of sections. The number of sections contained in the table view after the update (2) must be equal to the number of sections contained in the table view before the update (3), plus or minus the number of sections inserted or deleted (0 inserted, 0 deleted).'
I don't get the (0 inserted, 0 deleted) part. Why wouldn't it work ?
Thanks
You should update the table data at the same time. If you are using an array object for each row, remove the deleted one from the array.
The error means what it says:
The number of sections contained in the table view after the update (2) must be equal to the number of sections contained in the table view before the update (3), plus or minus the number of sections inserted or deleted (0 inserted, 0 deleted).'
This is probably one of the better error messages out there and it basically means that the amount data backing your table view is out of sync with it's state in the UI, specifically the number of sections (hint: check –numberOfSectionsInTableView:) before/after your delete. If you delete a row/section from the table, you need to make sure you delete that row/section from the data backing the table.
(0 inserted, 0 deleted)
Means that the API didn't find that your data source had any deleted sections.
Are you absolutely certain that is doing what you think it is doing:
[self deleteModelForIndexPath:indexPath];
You shouldn't use beginUpdates and endUpdates methods for such an operation. You should simply do:
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
if (editingStyle == UITableViewCellEditingStyleDelete)
{
[self deleteModelForIndexPath:indexPath];
[mainTableView deleteRowsAtIndexPaths:#[indexPath] withRowAnimation:UITableViewRowAnimationTop];
}
}
Also you can take a look at the documentation about beginUpdates:
Call this method if you want subsequent insertions, deletion, and
selection operations (for example, cellForRowAtIndexPath: and
indexPathsForVisibleRows) to be animated simultaneously. This group of
methods must conclude with an invocation of endUpdates. These method
pairs can be nested. If you do not make the insertion, deletion, and
selection calls inside this block, table attributes such as row count
might become invalid. You SHOULD NOT call reloadData within the group;
if you call this method within the group, you will need to perform any
animations yourself.
Hi the following function doesn´t work for me and i don´t get why....
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
if (editingStyle == UITableViewCellEditingStyleDelete)
{
// Delete the row from the data source
NSString *selectedCategory = [self.daten objectAtIndex:indexPath.row];
[self.daten removeObjectAtIndex:indexPath.row]; //we assume, that mySourceArray is a NSMutableArray we use as our data source
[self.tableView beginUpdates];
[self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
[self.tableView endUpdates];
// ...
}
}
I don´t have any Sections...I always get that exception:
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 (19) must be equal to the number of rows contained in that section before the update (19), 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).'
* First throw call stack:
(0x342692a3 0x33a3b97f 0x3426915d 0x3922e2af 0x36dd5b83 0x5453d 0x36f6b5d9 0x36e8c0ad 0x36e8c05f 0x36e8c03d 0x36e8b8f3 0x36e8c0ad 0x36e8c05f 0x36e8c03d 0x36e8b8f3 0x36e8bde9 0x36db45f9 0x36da1809 0x36da1123 0x34f195a3 0x34f191d3 0x3423e173 0x3423e117 0x3423cf99 0x341afebd 0x341afd49 0x34f182eb 0x36df5301 0x24343 0x38e34b20)
libc++abi.dylib: terminate called throwing an exception
You need to update your number of rows in numberOfRowsInSection: method. As i can see, you need to return your [self.daten count] in this method.
As its told, the system checks this number before/after update/delete to keep data integrity.
You always have a section :)
Implement it like this:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [self.daten count];
}
Also, remember that you need to set both UITableViewDelegate and UITableViewDataSource to self.
OK, the problem is: NSMutableArray's removeObjectAtIndex: method does not resize it. So you have to handle it by yourself. Create new array with right capacity and move the rest of elements to it. You can google how to resize NSMutableArray.