UITableView: excluindo seções com animação

Atualizar

Eu postei minha solução para este problema como uma resposta abaixo. É preciso uma abordagem diferente da minha primeira revisão.

Pergunta original Eu já fiz uma pergunta no SO que achei que resolveu meus problemas:

Como lidar com linhas não visíveis durante a exclusão de linha. (UITableViews)

No entanto, agora tenho problemas semelhantes novamente ao remover seções de um UITableView. (eles ressurgiram quando eu variei o número de seções / linhas na tabela).

Antes de eu perder você por causa do tamanho do meu post, deixe-me declarar o problema claramente, e você pode ler o quanto precisar para fornecer uma resposta.

Problema:

Se em lote excluir linhas e seções de um UITableView, o aplicativo falha, às vezes. Depende da configuração da tabela e da combinação de linhas e seções que escolho remover.

O log diz que eu falhei porque diz que não atualizei a fonte de dados e a tabela corretamente:

Invalid update: invalid number of rows in section 5.  The number of rows contained in an existing section after the update (2) 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, 0 deleted).

Agora, rapidamente, antes de escrever a resposta óbvia, garanto que realmente adicionei e excluí as linhas e seções corretamente do dataSource. A explicação é longa, mas você a encontrará abaixo, seguindo o método.

Então, com isso, se você ainda está interessado ...

Método que manipula a remoção de seções e linhas:

- (void)createFilteredTableGroups{

    //index set to hold sections to remove for deletion animation
    NSMutableIndexSet *sectionsToDelete = [NSMutableIndexSet indexSet];
    [sectionsToDelete removeIndex:0];


    //array to track cells for deletion animation
    NSMutableArray *cellsToDelete = [NSMutableArray array];

    //array to track controllers to delete from presentation model
    NSMutableArray *controllersToDelete = [NSMutableArray array];

    //for each section
    for(NSUInteger i=0; i<[tableGroups count];i++){

        NSMutableArray *section = [tableGroups objectAtIndex:i];

        //controllers to remove
        NSMutableIndexSet *controllersToDeleteInCurrentSection = [NSMutableIndexSet indexSet];
        [controllersToDeleteInCurrentSection removeIndex:0];
        NSUInteger indexOfController = 0;

        //for each cell controller
        for(ScheduleCellController *cellController in section){

            //bool indicating whether the cell controller's cell should be removed
            NSString *shouldDisplayString = (NSString*)[[cellController model] objectForKey:@"filteredDataSet"];
            BOOL shouldDisplay = [shouldDisplayString boolValue];

            //if it should be removed
            if(!shouldDisplay){

                NSIndexPath *cellPath = [self indexPathOfCellWithCellController:cellController]; 

                //if cell is on screen, mark for animated deletion
                if(cellPath!=nil)
                    [cellsToDelete addObject:cellPath];

                //marking controller for deleting from presentation model
                [controllersToDeleteInCurrentSection addIndex:indexOfController];                

            }
            indexOfController++;
        }

        //if removing all items in section, add section to removed in animation
        if([controllersToDeleteInCurrentSection count]==[section count])
            [sectionsToDelete addIndex:i];

        [controllersToDelete addObject:controllersToDeleteInCurrentSection];

    }


    //copy the unfiltered data so we can remove the data that we want to filter out
    NSMutableArray *newHeaders = [tableHeaders mutableCopy];
    NSMutableArray *newTableGroups = [[allTableGroups mutableCopy] autorelease];


    //removing controllers
    int i = 0;
    for(NSMutableArray *section in newTableGroups){
        NSIndexSet *indexesToDelete = [controllersToDelete objectAtIndex:i];
        [section removeObjectsAtIndexes:indexesToDelete];
        i++;
    }

    //removing empty sections and cooresponding headers
    [newHeaders removeObjectsAtIndexes:sectionsToDelete];
    [newTableGroups removeObjectsAtIndexes:sectionsToDelete];

    //update headers
    [tableHeaders release];
    tableHeaders = newHeaders;

    //storing filtered table groups
    self.filteredTableGroups = newTableGroups;


    //filtering animation and presentation model update
    [self.tableView beginUpdates];
    tableGroups = self.filteredTableGroups;
    [self.tableView deleteSections:sectionsToDelete withRowAnimation:UITableViewRowAnimationTop];
    [self.tableView deleteRowsAtIndexPaths:cellsToDelete withRowAnimation:UITableViewRowAnimationTop];
    [self.tableView endUpdates];


    //marking table as filtered
    self.tableIsFiltered = YES; 


}

Meu palpite:

O problema parece ser este: se você olhar acima onde eu listo o número de células em cada seção, você verá que a seção 5 parece aumentar em 1. No entanto, isso não é verdade. A seção original 5 foi realmente excluída e outra seção tomou seu lugar (especificamente, é antiga seção 10).

Então, por que a visão da mesa parece não perceber isso? Deve saber que eu removi a seção antigae não deve esperar que uma nova seção que agora está localizada no índice da seção antiga seja limitada pelo número de linhas da seção excluída.

Espero que isso faça sentido, é um pouco complicado escrever isso.

(note que este código trabalhou antes com um número diferente de linhas / seções. Esta configuração particular parece dar problemas)

questionAnswers(7)

yourAnswerToTheQuestion