代码之家  ›  专栏  ›  技术社区  ›  Frank Schmitt

基于核心数据对象的UITableView单元格插入/删除算法?

  •  1
  • Frank Schmitt  · 技术社区  · 15 年前

    我有一个核心数据配方对象,它包含一个成分对象的有序列表。

    配料在UITableView中显示为列表。当用户取消编辑表视图时,我调用 rollback 在MOC上,它可以恢复一些成分(用户删除的任何成分)并删除其他成分(用户添加的任何成分)。我想动画的插入/删除,以便过渡是不是不和谐。

    这比一开始看起来要难一点,特别是当你插入和移除同一个单元格时,UITableView会砍掉一个毛球。

    有没有一些示例代码可以帮助我朝着正确的方向发展?现在,我有一个可笑的复杂设置使用NSMutableSets是不是很正常工作。

    NSMutableArray *preIngredients = [NSMutableArray arrayWithArray:[recipe orderedIngredients]];
    
    [self.recipe.managedObjectContext rollback];
    
    NSMutableArray *postIngredients = [NSMutableArray arrayWithArray:[recipe orderedIngredients]];
    
    NSMutableSet *beforeIngredients = [NSMutableSet setWithArray:preIngredients];
    NSMutableSet *afterIngredients = [NSMutableSet setWithArray:postIngredients];
    
    NSMutableSet *restoredIngredients = [NSMutableSet setWithSet:afterIngredients];
    [restoredIngredients minusSet:beforeIngredients];
    
    NSMutableSet *removedIngredients = [NSMutableSet setWithSet:beforeIngredients];
    [removedIngredients minusSet:afterIngredients];
    
    NSMutableSet *allIngredients = [NSMutableSet setWithSet:beforeIngredients];
    [allIngredients unionSet:afterIngredients];
    
    int whatToDo[[preIngredients count]];
    for (int i = 0; i < [preIngredients count]; i++)
        whatToDo[i] = 0;
    
    for (Ingredient *ingredient in preIngredients) {
        int row = [preIngredients indexOfObject:ingredient];
    
        if ([removedIngredients containsObject:ingredient])
            whatToDo[row]--;
    
        if ([restoredIngredients containsObject:ingredient])
            whatToDo[row]++;
    }
    
    for (int i = 0; i < [preIngredients count]; i++) {
        if (whatToDo[i] < 0)
            [rowsToRemove addObject:[NSIndexPath indexPathForRow:i inSection:0]];
        else if (whatToDo[i] > 0)
            [rowsToRestore addObject:[NSIndexPath indexPathForRow:i inSection:0]];
    }
    
        // Also remove the "add new ingredient" cell
    NSIndexPath *insertNewCellIndexPath = [NSIndexPath indexPathForRow:[preIngredients count] inSection:0];
    if ([rowsToRestore indexOfObjectIdenticalTo:insertNewCellIndexPath] == NSNotFound)
        [rowsToRemove addObject:insertNewCellIndexPath];
    else
        [rowsToRestore removeObjectIdenticalTo:insertNewCellIndexPath];
    
    [self.tableView insertRowsAtIndexPaths:rowsToRestore withRowAnimation:UITableViewRowAnimationTop];
    [self.tableView deleteRowsAtIndexPaths:rowsToRemove withRowAnimation:UITableViewRowAnimationTop];
    
    2 回复  |  直到 15 年前
        1
  •  2
  •   Marcus S. Zarra    15 年前

    你考虑过使用 NSUndoManager documentation 在这个功能上。

    更新

    使用NSUndoManager一点也不复杂。开始分组,然后结束分组。如果需要,可以回滚这些更改。一对夫妇的代码行相比,跟踪你正在试图做的手。

        2
  •  1
  •   Frank Schmitt    15 年前

    这是大量使用集合的工作代码。如果你知道一个简化的方法,不要犹豫说出来:)

    [self.tableView beginUpdates];
    
    NSMutableArray *preIngredients = [NSMutableArray arrayWithArray:[recipe orderedIngredients]];
    [self.recipe.managedObjectContext rollback];
    NSMutableArray *postIngredients = [NSMutableArray arrayWithArray:[recipe orderedIngredients]];
    
    NSMutableSet *beforeIngredients = [NSMutableSet setWithArray:preIngredients];
    NSMutableSet *afterIngredients = [NSMutableSet setWithArray:postIngredients];
    
    NSMutableSet *ingredientsToRestore = [NSMutableSet setWithSet:afterIngredients];
    [ingredientsToRestore minusSet:beforeIngredients];
    
    NSMutableSet *ingredientsToRemove = [NSMutableSet setWithSet:beforeIngredients];
    [ingredientsToRemove minusSet:afterIngredients];
    
    NSMutableSet *indexPathsToRestore = [NSMutableSet setWithCapacity:[ingredientsToRestore count]];
    NSMutableSet *indexPathsToRemove = [NSMutableSet setWithCapacity:[ingredientsToRemove count]];
    
    for (Ingredient *ingredient in ingredientsToRemove)
        [indexPathsToRemove addObject:[NSIndexPath indexPathForRow:[preIngredients indexOfObject:ingredient] inSection:0]];
    
    // Also remove the "add new ingredient" row
    [indexPathsToRemove addObject:[NSIndexPath indexPathForRow:[preIngredients count] inSection:0]];
    
    for (Ingredient *ingredient in ingredientsToRestore)
        [indexPathsToRestore addObject:[NSIndexPath indexPathForRow:[postIngredients indexOfObject:ingredient] inSection:0]];
    
    NSMutableSet *commonIndexPaths = [NSMutableSet setWithSet:indexPathsToRemove];
    [commonIndexPaths intersectSet:indexPathsToRestore];
    
    [indexPathsToRemove minusSet:commonIndexPaths];
    [indexPathsToRestore minusSet:commonIndexPaths];
    
    [self.tableView insertRowsAtIndexPaths:[indexPathsToRestore allObjects] withRowAnimation:UITableViewRowAnimationTop];
    [self.tableView deleteRowsAtIndexPaths:[indexPathsToRemove allObjects] withRowAnimation:UITableViewRowAnimationTop];
    
    [self.tableView endUpdates];