aktualisierenUITableView: Löschen von Abschnitten mit Animation
Ich habe meine Lösung für dieses Problem als Antwort unten geschrieben. Es hat einen anderen Ansatz als meine erste Revision.
Original Question ich vorher eine Frage auf SO darum gebeten, dass ich dachte, meine Probleme gelöst:
How to deal with non-visible rows during row deletion. (UITableViews)
Allerdings habe ich jetzt ähnlich wieder Probleme, wenn Abschnitte von einem UITableView zu entfernen. (sie tauchten wieder auf, wenn ich die Anzahl der Abschnitte/Reihen in der Tabelle änderte).
Bevor ich Sie wegen der Scherlänge von meinem Posten zu verlieren, lassen Sie mich das Problem deutlich machen, und man kann so viel lesen, wie Sie eine Antwort geben erfordern.
Problem:
Wenn Batch-Zeilen und Abschnitte aus einer UITableView löschen, die Anwendung abstürzt, manchmal. Dies hängt von der Konfiguration der Tabelle und der Kombination von Zeilen und Abschnitten ab, die ich entfernen möchte.
Das Protokoll sagt, ich abgestürzt, weil es sagt, ich habe nicht die Datenquelle und die Tabelle korrekt aktualisiert:
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).
Jetzt schnell, bevor Sie die offensichtliche Antwort schreiben, ich versichern Ihnen, ich habe in die Tat hinzugefügt und gelöscht die Zeilen und Abschnitte ordnungsgemäß von der DataSource. Die Erklärung ist langwierig, aber Sie werden es unten finden und der Methode folgen.
Also mit diesem, wenn Sie noch interessiert ...
Methode, die Entfernung von Abschnitten und Zeilen Griffe:
- (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 em scheint das zu sein: Wenn Sie oben nachsehen, wo ich die Anzahl der Zellen in jedem Abschnitt aufliste, werden Sie sehen, dass Abschnitt 5 um 1 zu erhöhen scheint. Dies ist jedoch nicht wahr. Der ursprüngliche Abschnitt 5 wurde tatsächlich gelöscht und ein anderer Abschnitt hat seinen Platz eingenommen (speziell ist es der alte Abschnitt 10).
Warum scheint die Tabellenansicht dies nicht zu erkennen? Es sollte wissen, dass ich den alten Abschnitt und entfernt habe, sollte nicht erwarten, dass ein neuer Abschnitt, der jetzt im Index des alten Abschnitts liegt, an die Anzahl der Zeilen des gelöschten Abschnitts gebunden ist.
Hoffentlich macht Sinn, es ist ein wenig kompliziert ist, dies zu schreiben.
(beachten Sie, dass dieser Code zuvor mit einer anderen Anzahl von Zeilen/Abschnitten gearbeitet hat.Diese spezielle Konfiguration scheint es Probleme zu geben)
Verfolgen Sie alternativ den IndexPath für jede Zelle, die Sie loswerden müssen, und passen Sie sie entsprechend an, wenn Sie Ihre Löschungen durchlaufen. (Dies könnte die lange/gewundene/unangemessene Art sein, dies zu tun - nur ein Gedanke.) – Tim
Ich mache eine Batch-Löschung, so dass es keinen Unterschied macht, in welcher Reihenfolge ich die Operationen listet. Die Tabellenansicht führt Operationen "sofort" aus, wenn sie sich innerhalb des Aktualisierungsblocks befinden. Da ich paranoid war, habe ich versucht, die Reihenfolge der Operationen umsonst zu ändern. Die Nummerierung der Abschnitte/Zeilen wechselt während des Batch-Löschens nicht (sollte nicht wechseln). Wenn Sie die Blöcke nicht benutzen würden, wären Sie richtig. –
@Tim Interessanter Gedanke. Du hast Recht, das könnte ziemlich mühsam sein mit einer großen Anzahl von Löschungen (die ich haben werde). Ich frage mich auch, ob ich mehrere Streichungen in schneller Folge machen könnte. Ich habe versucht, Batch-Löschungen durchzuführen, um diese Probleme zu vermeiden, aber es kann notwendig sein. –