Error "Invalid update: Invalid number of rows in section 0" trying to delete a row in a table.

My code looks fine, but when I scroll to delete a row in my UITableView, the application crashes with the following:

Mistake

LittleToDoApp [70390: 4116002] *** Application termination due to an uncaught exception "NSInternalInconsistencyException", reason: "Invalid update: invalid number of lines in section 0. The number of lines contained in an existing section after update (1) must be equal to the number of lines contained in this section before updating (1), plus or minus the number of rows inserted or deleted from this section (0 inserted, 1 deleted) and plus or minus the number of rows moved to or from this section (0 moved, 0 deleted) .

ViewController.m

#import "ViewController.h" #import "ToDoItem.h" #import "ToDoItemSvcCache.h" @interface ViewController () @end @implementation ViewController @synthesize tableView; ToDoItemSvcCache *ToDoItemSvc = nil; - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view, typically from a nib. ToDoItemSvc = [[ToDoItemSvcCache alloc] init]; } - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; // Dispose of any resources that can be recreated. } - (IBAction)deleteToDoItem:(id)sender { NSLog(@"Deleting ToDoItem"); [self.view endEditing:YES]; } - (IBAction)addToDoItem:(id)sender { [self.view endEditing:YES]; NSLog(@"saveToDoItem: entering"); ToDoItem *todoitem = [[ToDoItem alloc] init]; todoitem.todoitem = _toDoItem.text; [ToDoItemSvc createToDoItem:todoitem]; [self.tableView reloadData]; NSLog(@"saveToDoItem: todoitem saved"); } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { static NSString *simpleTableIdentifier = @"toDoItemCell"; UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier]; if (cell == nil) { cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:simpleTableIdentifier]; } ToDoItem *toDoItem = [[ToDoItemSvc retrieveAllToDoItems] objectAtIndex:indexPath.row]; cell.textLabel.text = [toDoItem description]; return cell; } - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return [[ToDoItemSvc retrieveAllToDoItems] count]; } - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { return 1; } - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { if ([segue.identifier isEqualToString:@"viewToDoItem"]) { NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow]; SecondViewController *destViewController = segue.destinationViewController; UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath]; destViewController.toDoItemName = cell.textLabel.text; } } #pragma hiding status bar - (BOOL)prefersStatusBarHidden { return YES; } // here we get back from both styles - (IBAction)unwindFromDetailViewController:(UIStoryboardSegue *)segue { // UIViewController *detailViewController = [segue sourceViewController]; NSLog(@"%@", segue.identifier); } //Allows the delete button to show up when left swipping a list item - (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath { // Return YES - we will be able to delete all rows return YES; } - (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath { // Will add code to actually delete a row here. Adding NSLog so we know its triggering though NSLog(@"Deleted row."); [self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade]; [self.tableView reloadData]; } @end 

ToDoItemSvc.h

 #import <Foundation/Foundation.h> #import "ToDoItem.h" @protocol ToDoItemSvc <NSObject> - (ToDoItem *) createToDoItem: (ToDoItem *) todoitem; - (NSMutableArray *) retrieveAllToDoItems; - (ToDoItem *) updateToDoItem: (ToDoItem *) todoitem; - (ToDoItem *) deleteToDoItem: (ToDoItem *) todoitem; @end 

Full source

https://github.com/martylavender/LittleToDoApp/tree/Storyboards

Edit

Following the comments made by Fenelousky, do I need to do something in this direction?

 - (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath { if (editingStyle == UITableViewCellEditingStyleDelete) { [self.toDoItem removeObjectAtIndex:indexPath.row]; [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationLeft]; [self.tableView reloadData]; } } 

Edit 2

This is what I get:

https://www.evernote.com/l/AJiah58lVhdGXIYO1F5yv6fJXc7k3WjRLNYB/image.png

+8
ios objective-c uitableview
source share
2 answers

The number of rows in your table [[ToDoItemSvc retrieveAllToDoItems] count] . When you delete row 1 in your table, the number of rows in your table should be 1 less than the number of rows before deleting any rows. After deleting row 1 and calling [self.tableView reloadData] tableView checks how many rows are in the table. At this point, numberOfRowsInSection will return [[ToDoItemSvc retrieveAllToDoItems] count] . Now it should be 1 less than it was before the row was deleted.

Short answer: first you need to remove the item from your data source that looks like [ToDoItemSvc retrieveAllToDoItems] , and then delete the row.

In addition to this, when you add a row, you need to add an element to your data source.

These changes must occur before calling reloadData .

Edit

 - (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath { // Actually remove the data from the source [ToDoItemSvc deleteToDoItem:[ToDoItemSvc retrieveAllToDoItems][indexPath.row]] [self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade]; [self.tableView reloadData]; } 

ELI5: The teacher has five students: Alice, Bob, Charlie, Diana and Eric. Bob's mom picks him up early from school before lunch. After lunch, the teacher takes part and panic, because he has only four children, when the list says that there should be five. Where is bob ?!

If Bob's mom removed his name from the list when she pulled him out of school, then the teacher would not panic.

+14
source share

I figured this out with help from above and reflection.

First I finished the actual deleteToDoItem code

 - (ToDoItem *) deleteToDoItem: (ToDoItem *) todoitem { [ToDoItems removeObject:todoitem]; return todoitem; } 

Then the code above

 - (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath { ToDoItem *toDoItem = [[ToDoItemSvc retrieveAllToDoItems] objectAtIndex:indexPath.row]; [ToDoItemSvc deleteToDoItem:toDoItem]; [self.tableView reloadData]; NSLog(@"Removing data"); } 

This is done and allows me to delete my element as I want!

+2
source share

All Articles