在 commitEditingStyle 中延迟模型和 table 视图更改

Delaying the model and table view change in commitEditingStyle

模型变化和行动画是否必须直接从commitEditingStyle开始,还是可以在以后的运行循环迭代中完成?

我问是因为它似乎在 iOS 10 上有效,但在 iOS 11 上它至少破坏了删除动画。它只是 iOS 11 中的一个错误还是一般来说是个坏主意?

是否有更好的方法来触发异步删除操作并在完成时为 table 视图更改设置动画?


第一张图片显示了它如何在 iOS 11 处中断(删除按钮与下一个单元格重叠)。第二张图片显示了它在 iOS 10 上的表现如何。




这是有趣的片段:

- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
    if (editingStyle == UITableViewCellEditingStyleDelete) {
        dispatch_async(dispatch_get_main_queue(), ^{
            [_model removeObjectAtIndex:indexPath.row];
            [tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade];
        });
    }
}



如果我删除 dispatch_async(...,它会在 iOS 10 和 11 上按预期工作。第一张图片显示 iOS 11,第二张图片显示 iOS 10。




这是用于测试它的 table 视图控制器的完整代码:

#import "TableViewController.h"

@implementation TableViewController {
    NSMutableArray<NSString *>* _model;
}

- (void)viewDidLoad {
    [super viewDidLoad];
    _model = [[NSMutableArray alloc] init];
    [self.tableView registerClass:UITableViewCell.class forCellReuseIdentifier:@"cell"];

    for (NSInteger i = 0; i < 200; i++) {
        [_model addObject:[NSString stringWithFormat:@"Test Row %ld Test Test Test Test Test", (long)i]];
    }
}

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
    return 1;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    return _model.count;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cell" forIndexPath:indexPath];
    cell.textLabel.text = _model[indexPath.row];
    return cell;
}

- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath {
    return YES;
}

- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
    if (editingStyle == UITableViewCellEditingStyleDelete) {
        dispatch_async(dispatch_get_main_queue(), ^{
            [_model removeObjectAtIndex:indexPath.row];
            [tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade];
        });
    }
}

@end



更新:
将此方法添加到 table 视图控制器可修复 iOS 11 并允许延迟模型更改和行动画。 (感谢 ChrisHaze)

- (UISwipeActionsConfiguration *)tableView:(UITableView *)tableView trailingSwipeActionsConfigurationForRowAtIndexPath:(NSIndexPath *)indexPath NS_AVAILABLE_IOS(11_0) {
    UIContextualAction* deleteAction = [UIContextualAction contextualActionWithStyle:UIContextualActionStyleDestructive title:@"Delete" handler:^(UIContextualAction * _Nonnull action, __kindof UIView * _Nonnull sourceView, void (^ _Nonnull completionHandler)(BOOL)) {
        dispatch_async(dispatch_get_main_queue(), ^{
            [_model removeObjectAtIndex:indexPath.row];
            [tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade];
            completionHandler(YES);
        });
    }];
    UISwipeActionsConfiguration* config = [UISwipeActionsConfiguration configurationWithActions:@[deleteAction]];
    return config;
}

iOS11 中的 UITable 视图似乎发生了变化。

Apple 的构建版本说明:

"The behavior of the delete swipe action has been changed.When implementing commitEditingStyle: to delete a swiped row, delete the row in the data source and call deleteRowsAtIndexPaths: on the table view to show the swipe delete animation."

经过进一步研究,我发现必须在调用 deleteRowAtIndexPath: 方法之前调用 beginUpdates,然后再调用 endUpdates 方法。

根据 Apple 的 documentation,不调用这些 tableView 方法将导致潜在的数据模型问题并影响删除动画。

话虽如此,有一个 answer 包含 Apple 开发论坛上一个问题所需的代码,该问题解决了一个非常相似的问题。


回答您的实际问题:

  • 需要在 beginUpdates 和 endUpdates 块之前调用模型更改,其中将发生 UI 更改。
  • 更新 UITable 视图将缓解 synchronization/animation 问题。

---------------------------- additional details------------ --------------

在查看了您评论中的详细信息后,我提供了一个 link(上图),这是 Apple 提供的最新 Table 查看编程指南。它将带您或遇到此问题的任何其他人到指南的部分,其中包含您添加到问题中的详细信息。

还有一个方便的 note,其中包括如何在必须时从 commitEditingStyle 方法中进行 deleteRowAtIndexPath 调用。