views:

32

answers:

1

I have a UITableView with 2 sections. The section 0 contains a list of file names and the user can tap them to toggle the checkmark accessory. This section is also editable so the user can swipe to delete a file/row. The section 1 is not editable and contains 1 row and acts as a button to initiate a transfer of the files.

Thus, the datasource for the table looks like this:

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {

switch (section) {
    case SECTION_FILES:
        return [files count];
        break;
    case SECTION_ACTIONS:
        if ([files count]) {
            return 1;       // ROW_ACTIONS_TRANSFER
        return 0;
        break;
}
return 0;

}

The behavior that I want is for section 1 to display only when section 0 has rows. The problem I'm finding is that when the last row in section 0 is removed section 1 still contains 1 row. To remove the row from section 1 I figured I should either call deleteRowsAtIndexPath or reloadSections while committing the edit for the last row in section 0 and then the cell would be animated out. However, doing this causes my app to crash saying:

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

I can call reloadData on the tableview, but the update is a drastic redraw and I would much prefer to animate the cells out. Is there a way to accomplish what I want? I feel like this should be easy and I'm missing something obvious.

My commitEditingStyle code is below. I delete from my datasource (files) first, that is the recommended way, right?

- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
    if (editingStyle == UITableViewCellEditingStyleDelete) {
        switch ([indexPath section]) {
            case SECTION_FILES:
                [files removeObjectAtIndex:indexPath.row];
                [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationRight];
                // Here is where I would call [tableView reloadData] or [tableView reloadSection...
                break;
        }

} }

A: 

I was able to solve this on my own, but not in as elegant a way as I wanted. Essentially, what I do is keep a member variable to track whether or not I have inserted SECTION_ACTIONS into the tableview. Then when SECTION_FILES is modified I do:

[tableview beginUpdates];
[tableview insertSection SECTION_ACTIONS];
self.showingActionsSection = YES;
[tableview endUpdates];

or

[tableview beginUpdates];
[tableview deleteSection SECTION_ACTIONS];
self.showingActionsSection = NO;
[tableview endUpdates];

Luckily, doing it like this allows me to get nice smooth animations as things are added and removed. However, it makes UITableView datasource behave a little differently than I am used to.

Partridge