UITableView:删除带动画的部分

Cor*_*oyd 40 iphone cocoa-touch uitableview uikit

更新

我在下面的答案中发布了我的解决方案.我的第一次修订采用了不同的方法.


原始问题 我之前问了一个关于SO的问题我认为我解决了我的问题:

如何在删除行时处理不可见的行.(UITableViews)

但是,从UITableView中删除部分时,我现在又遇到了类似的问题.(当我改变表格中的部分/行数时,它们重新浮出水面).

在我因为我的帖子的剪切长度而失去你之前,让我清楚地说明问题,你可以尽可能多地阅读以提供答案.


问题:

如果从UITableView批量删除行和部分,应用程序有时会崩溃.这取决于表的配置以及我选择删除的行和部分的组合.

日志说我崩溃了,因为它说我没有正确更新数据源和表:

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).
Run Code Online (Sandbox Code Playgroud)

现在很快,在你写出明显的答案之前,我向你保证我确实已经从dataSource中正确添加和删除了行和部分.解释很冗长,但您可以按照方法在下面找到它.

那么,如果你仍然感兴趣......


处理部分和行的删除的方法:

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


}
Run Code Online (Sandbox Code Playgroud)

我猜:

问题似乎是这样的:如果你看一下我列出每个部分中单元格数量的位置,你会发现第5部分似乎增加了1.但是,这不是真的.原来的第5部分实际上已被删除,另一部分取而代之(具体来说,它是旧的第10部分).

那么为什么表格视图似乎没有意识到这一点呢?它应该知道我删除了旧的部分,并且不应期望现在位于旧部分索引的新部分受删除部分的行数限制.

希望这是有道理的,写出来有点复杂.

(请注意,此代码之前使用了不同数量的行/部分.这种特殊配置似乎给它带来了问题)

Mar*_*ter 88

我之前遇到过这个问题.您试图从一个部分删除所有行,然后,此外,现在是空的部分.但是,仅删除该部分就足够了(并且适当).其中的所有行也将被删除.以下是我的项目中的一些示例代码,用于处理删除一行.它需要确定是否应该从一个部分中删除该行,或者删除整个部分(如果它是该部分中的最后一行):

- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
    if (editingStyle == UITableViewCellEditingStyleDelete)
    {
        // modelForSection is a custom model object that holds items for this section.
        [modelForSection removeItem:[self itemForRowAtIndexPath:indexPath]];

        [tableView beginUpdates];

        // Either delete some rows within a section (leaving at least one) or the entire section.
        if ([modelForSection.items count] > 0)
        {
            // Section is not yet empty, so delete only the current row.
            [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath]
                             withRowAnimation:UITableViewRowAnimationFade];
        }
        else
        {
            // Section is now completely empty, so delete the entire section.
            [tableView deleteSections:[NSIndexSet indexSetWithIndex:indexPath.section] 
                     withRowAnimation:UITableViewRowAnimationFade];
        }

        [tableView endUpdates];
    }
}
Run Code Online (Sandbox Code Playgroud)