UITableView commitEditingStyle: used with expanding and collapsing sections

35 Views Asked by At

I have a UITableView with expanding and collapsing sections. Each section header is actually the row at index 0 for each section. Let's say that section contains six items, tapping on the header row (index 0) causes and additional six rows to be added to the section, making seven in total. This is working beautifully, it looks good and the expanding and collapsing is smooth and clean. The code is mostly based on what can be seen here: https://www.cocoanetics.com/2011/03/expandingcollapsing-tableview-sections

The key part of this is that the indexes of the sections which are expanded at any given time are stored in an NSMutableIndexSet. So every time the table view loads, it queries self.expandedSections to see if it should load all the rows, showing the folder contents, or just the first row containing the name of the folder.

The problem comes when the user needs to delete a folder. If the table view contains any expanded sections with an index higher than the folder being deleted, I get a crash with the following:

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

This error is pretty self-explanatory, indeed someone at Apple has gone to some effort to make it as unambiguous as possible. However, I can't find a way around it. Code for deleting looks like this:

if (editingStyle == UITableViewCellEditingStyleDelete)
{
    if (indexPath.row == 0) // we are deleting a folder
    {
        NSString *folderPath = [self.sectionHeaders objectAtIndex:indexPath.section];
        NSError *error = nil;
        if (![self.fileManager removeItemAtPath:folderPath error:&error]) [self.delegate alertForError:error];
        else
        {
            [self.sectionHeaders removeObjectAtIndex:indexPath.section]; // remove array reference to folder
            [self.expandedSections removeIndex:indexPath.section];

            // crashes if some other folder is displaying its contents
            [tableView deleteSections:[NSIndexSet indexSetWithIndex:indexPath.section] withRowAnimation:UITableViewRowAnimationAutomatic];
       }
    }
    else // we are deleting a file
    {
        etc...
    }
}

This is called inside tableView:commitEditingStyle:forRowAtIndexPath:

Any suggestions much appreciated!

1

There are 1 best solutions below

0
beev On

Solved it. Although I was removing the deleted section from self.expandedSections, I needed to also update the other values in the set, if they were higher than the value being deleted. I also need to update the array of arrays representing the contents of folders.

            [self.sectionHeaders removeObjectAtIndex:indexPath.section]; // remove array reference to folder
            [_arrayOfFolderContentsArrays removeObjectAtIndex:indexPath.section];

            // for each index in expandedSections, we need to reduce the value of those higher than the section being deleted
            NSMutableIndexSet *tempSet = [[NSMutableIndexSet alloc] init];
            [self.expandedSections enumerateIndexesUsingBlock:^(NSUInteger idx, BOOL * _Nonnull stop) {
                // repopulate expandedSections without section that is being deleted
                if (idx > (NSUInteger)indexPath.section)
                {
                    idx--;
                    [tempSet addIndex:idx];
                }
                else if (idx < (NSUInteger)indexPath.section)
                {
                    [tempSet addIndex:idx];
                }
            } ];

            self.expandedSections = tempSet;

            // remove table view section
            [tableView deleteSections:[NSIndexSet indexSetWithIndex:indexPath.section] withRowAnimation:UITableViewRowAnimationAutomatic];