UITableView: Löschen von Abschnitten mit Animation

Aktualisieren

Ich habe meine Lösung für dieses Problem unten als Antwort veröffentlicht. Es hat einen anderen Ansatz als meine erste Revision.

Ursprüngliche Frage Ich habe zuvor eine Frage zu SO gestellt, die meiner Meinung nach meine Probleme gelöst hat:

Umgang mit nicht sichtbaren Zeilen beim Löschen von Zeilen. (UITableViews)

Allerdings habe ich jetzt wieder ähnliche Probleme beim Entfernen von Abschnitten aus einer UITableView. (Sie tauchten wieder auf, als ich die Anzahl der Abschnitte / Zeilen in der Tabelle veränderte.)

Bevor ich Sie wegen der Scherlänge meines Postens verliere, lassen Sie mich das Problem klar darlegen, und Sie können so viel lesen, wie Sie benötigen, um eine Antwort zu geben.

Problem:

Wenn Sie Zeilen UND Abschnitte in einer UITableView stapelweise löschen, stürzt die Anwendung manchmal ab. Dies hängt von der Konfiguration der Tabelle und der Kombination von Zeilen und Abschnitten ab, die ich entfernen möchte.

Das Protokoll besagt, dass ich abgestürzt bin, weil ich die Datenquelle und die Tabelle nicht richtig aktualisiert habe:

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

Bevor Sie die offensichtliche Antwort schreiben, versichere ich Ihnen, dass ich die Zeilen und Abschnitte tatsächlich ordnungsgemäß zur dataSource hinzugefügt und daraus gelöscht habe. Die Erklärung ist langwierig, aber Sie werden sie unten finden, wenn Sie der Methode folgen.

Also damit, wenn Sie noch interessiert sind ...

Methode zum Entfernen von Abschnitten und Zeilen:

- (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; 


}

Meine Vermutung:

Das Problem scheint folgendes zu sein: Wenn Sie nach oben schauen, wo ich die Anzahl der Zellen in jedem Abschnitt aufführe, werden Sie feststellen, dass Abschnitt 5 anscheinend um 1 zunimmt. Dies ist jedoch nicht der Fall. Der ursprüngliche Abschnitt 5 wurde tatsächlich gelöscht, und ein anderer Abschnitt ist an seine Stelle getreten (insbesondere der alte Abschnitt 10).

Warum scheint die Tabellenansicht dies nicht zu erkennen? Es sollte WISSEN, dass ich den alten Abschnitt entfernt habeund Es sollte nicht erwartet werden, dass ein neuer Abschnitt, der sich jetzt im Index des alten Abschnitts befindet, an die Anzahl der Zeilen des gelöschten Abschnitts gebunden ist.

Hoffentlich macht das Sinn, es ist ein bisschen kompliziert, das aufzuschreiben.

(Beachten Sie, dass dieser Code zuvor mit einer anderen Anzahl von Zeilen / Abschnitten funktioniert hat. Diese spezielle Konfiguration scheint Probleme zu verursachen.)

Antworten auf die Frage(7)

Ihre Antwort auf die Frage