sudo rm -rf
sudo rm -rf

Reputation: 29524

NSInternalInconsistencyException (invalid number of rows)

Whenever I have data in my UITableView and I start deleting, it works fine. However, when I get to the last object in the table, and delete it, it crashes.

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).'

Here's how I'm doing the editing stuff:

-(void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
    if (editingStyle == UITableViewCellEditingStyleDelete) {
        // Delete the row from the data source
        if ([myData count] >= 1) {
            [tableView beginUpdates];
            [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
            [myData removeObjectAtIndex:[indexPath row]];

            NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
            NSString *documentsDirectory = [paths objectAtIndex:0];
            NSString *somepath = [documentsDirectory stringByAppendingPathComponent:@"something.plist"];
            [myData writeToFile:somepath atomically:YES];
            [table reloadData];
            if ([myData count] == 0) {
                [tableView endUpdates];
                [tableView reloadData];
            }
            else {
            [tableView endUpdates];
            }
        }
    }   
}

And also this:

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    // Return the number of rows in the section.
    if ([myData count] != 0) {
        return [myData count];
    }
    else {
        return 1;
    }
}

The reason I'm returning 1 is because I'm making a cell that says "No data saved" in cellForRowAtIndexPath. Here's what I mean:

-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    static NSString *CellIdentifier = @"Cell";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil) {
        cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
    }    
    if ([cityData count] != 0) {
        //normal setup removed for clarity
    }
    else {
        cell.textLabel.text = @"No saved data!";
    cell.textLabel.font = [UIFont boldSystemFontOfSize:14]; 
    cell.textLabel.textAlignment = UITextAlignmentCenter;
    cell.selectionStyle = UITableViewCellSelectionStyleNone;
        cell.tag = 1;
    return cell;
    }
}

So, what am I doing wrong in my editing code to get this error? Thanks!

Upvotes: 15

Views: 19779

Answers (3)

rjobidon
rjobidon

Reputation: 3155

The method tableView:numberOfRowsInSection must always return exact number of rows:

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    // Return the number of rows in the section.
    return [myData count];
}

After having deleted last row, you may want to delete the whole section. Simply call deleteSections:withRowAnimation: within a beginUpdates and endUpdated block;

-(void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
    if (editingStyle == UITableViewCellEditingStyleDelete) {
        // Delete the row from the data source
        [tableView beginUpdates];
        [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
        [myData removeObjectAtIndex:[indexPath row]];
        NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
        NSString *documentsDirectory = [paths objectAtIndex:0];
        NSString *somepath = [documentsDirectory stringByAppendingPathComponent:@"something.plist"];
        [myData writeToFile:somepath atomically:YES];
        if ([myData count] == 0) {
            // NEW! DELETE SECTION IF NO MORE ROWS!
            [tableView deleteSections:[NSIndexSet indexSetWithIndex:[indexPath section]] withRowAnimation:UITableViewRowAnimationFade];
        }
        [tableView endUpdates];
    }   
}

Upvotes: 1

Pidakar
Pidakar

Reputation: 11

first remove from myData and then delete from tableview.

-(void)tableView:(UITableView *)tableView commitEditingStyle: 
(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {

if (editingStyle == UITableViewCellEditingStyleDelete) {
        //somehting...
        [myData removeObjectAtIndex:[indexPath row]];
        [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
        //somehting...
    }
}   

}

Upvotes: 1

Cameron Spickert
Cameron Spickert

Reputation: 5200

If you delete the last row in your table, the UITableView code expects there to be 0 rows remaining. It calls your UITableViewDataSource methods to determine how many are left. Since you have a "No data" cell, it returns 1, not 0. So when you delete the last row in your table, try calling -insertRowsAtIndexPaths:withRowAnimation: to insert your "No data" row. Also, you should not call -reloadData anywhere in this method. -endUpdates will take care of reloading the affected rows. Try this out:

-(void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
    if (editingStyle == UITableViewCellEditingStyleDelete) {
        // Delete the row from the data source
        if ([myData count] >= 1) {
            [tableView beginUpdates];
            [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
            [myData removeObjectAtIndex:[indexPath row]];

            NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
            NSString *documentsDirectory = [paths objectAtIndex:0];
            NSString *somepath = [documentsDirectory stringByAppendingPathComponent:@"something.plist"];
            [myData writeToFile:somepath atomically:YES];

            if ([myData count] == 0) {
                [tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
            }
            [tableView endUpdates];
        }
    }   
}

Upvotes: 29

Related Questions