Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

UITableView crashes when trying to delete a cell and section

I've been working on creating a UITableView that has its content loaded from a NSUserDefaults object. Whenever I attempt to delete a cell/section, however, the program crashes and spits out the following:

*** Assertion failure in -[UITableView _endCellAnimationsWithContext:], /SourceCache/UIKit_Sim/UIKit-1912.3/UITableView.m:1030
*** 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).

No matter how much I read up on this error and try to fix it, I've been stuck here for the past few hours. Here is my method that is called when the user taps the "delete" button:

 (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
    if (editingStyle == UITableViewCellEditingStyleDelete) {
        //[[[NSUserDefaults standardUserDefaults] objectForKey:@"rawArray"] removeObjectAtIndex:indexPath.row];
        //[[[NSUserDefaults standardUserDefaults] objectForKey:@"rawDates"] removeObjectAtIndex:indexPath.row];

        NSMutableArray *rawArray = [[NSUserDefaults standardUserDefaults] objectForKey:@"rawArray"];
        NSMutableArray *rawDates = [[NSUserDefaults standardUserDefaults] objectForKey:@"rawDates"];

        [rawArray removeObjectAtIndex:indexPath.row];
        [rawDates removeObjectAtIndex:indexPath.row];

        [[NSUserDefaults standardUserDefaults] setObject:rawArray forKey:@"rawArray"];
        [[NSUserDefaults standardUserDefaults] setObject:rawDates forKey:@"rawDates"];

        [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationRight];
        [tableView deleteSections:[NSIndexSet indexSetWithIndex:indexPath.section] withRowAnimation:UITableViewRowAnimationRight];

    }    
}

and here are the methods used to determine number of rows and cells:

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
    return [[[NSUserDefaults standardUserDefaults] arrayForKey:@"rawDates"] count];
}

- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section{

    return [[[NSUserDefaults standardUserDefaults] arrayForKey:@"rawDates"] objectAtIndex:section];
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
    return 1;
}

The last method in there returns a one because, as of right now, I plan on only have one cell per each section. Thank you for taking the time to look over here, and I really hope you can help me out! :/

like image 858
insanj Avatar asked Dec 07 '22 15:12

insanj


1 Answers

Check out the Batch Insertion, Deletion, and Reloading of Rows and Sections

Basically you need to put any calls of these method

- (void)insertSections:(NSIndexSet *)sections withRowAnimation:(UITableViewRowAnimation)animation;
- (void)deleteSections:(NSIndexSet *)sections withRowAnimation:(UITableViewRowAnimation)animation;
- (void)reloadSections:(NSIndexSet *)sections withRowAnimation:(UITableViewRowAnimation)animation;

- (void)insertRowsAtIndexPaths:(NSArray *)indexPaths withRowAnimation: (UITableViewRowAnimation)animation;
- (void)deleteRowsAtIndexPaths:(NSArray *)indexPaths withRowAnimation: (UITableViewRowAnimation)animation;
- (void)reloadRowsAtIndexPaths:(NSArray *)indexPaths withRowAnimation:(UITableViewRowAnimation)animation;

between

- (void)beginUpdates;
- (void)endUpdates;

e.g.

[tableView beginUpdates];
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationRight];
[tableView deleteSections:[NSIndexSet indexSetWithIndex:indexPath.section] withRowAnimation:UITableViewRowAnimationRight];
[tableView endUpdates];

Your dataSource also needs to reflect the changes by the time endUpdates is called


Personally I like to make a category to give a block based wrapper around this to

  1. stop me forgetting to call endUpdates
  2. it allows indentation to look right / be automatic

Category on UITableView

@interface UITableView (PSAdditions)

- (void)ps_updates:(void (^)(void))updateBlock;

@end

@implementation UITableView (PSAdditions)

- (void)ps_updates:(void (^)(void))updateBlock;
{
    [self beginUpdates];
    if (updateBlock) { updateBlock(); }
    [self endUpdates];
}

Which would look like this

[tableView ps_updates:^{
    [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationRight];
    [tableView deleteSections:[NSIndexSet indexSetWithIndex:indexPath.section] withRowAnimation:UITableViewRowAnimationRight];
}];
like image 185
Paul.s Avatar answered Jan 01 '23 17:01

Paul.s