ios - 延迟 commitEditingStyle 中的模型和 TableView 更改

标签 ios objective-c uitableview asynchronous ios11

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

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

有没有更好的方法来触发异步删除操作并在完成时为 TableView 更改设置动画?

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

Delayed, broken on iOS 11
Delayed, looks fine on 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。

Direct, works on iOS 11
Direct, works on iOS 10

这是用于测试它的 TableView Controller 的完整代码:
#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 view controller 修复了 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;
}

最佳答案

iOS 11 中的 UITableview 似乎发生了变化。

Apple 的 Build 发行说明:

“删除滑动操作的行为已更改。实现commitEditingStyle:删除滑动行时,删除数据源中的行并在表格 View 上调用deleteRowsAtIndexPaths:以显示滑动删除动画。”

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

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

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

回答您的实际问题:

  • 模型更改需要在 beginUpdates 和 endUpdates block 之前调用,其中将发生 UI 更改。
  • 更新 UITableView 将缓解同步/动画问题。

  • ---------------------------------------- additional details ----------------------------

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

    还有一个好用的注意 其中包括如何制作 deleteRowAtIndexPathcommitEditingStyle 内调用电话如果必须的方法。

    关于ios - 延迟 commitEditingStyle 中的模型和 TableView 更改,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47147342/

    相关文章:

    ios - 一个 View Controller 中的两个表

    ios - CAEmitterCell - 慢星星或光效

    ios - 我的 UITableView 中的自定义标题 View 在底部绘制了额外的线

    ios - 使用 Facebook 电子邮件登录未返回

    objective-c - Swift 1.2 为什么我不能继承任何 NSCell 的子类?

    ios - 如何在tableview和viewcontroller之间传递字符串

    javascript - localStorage UIWebView iPhone/iPad 保存或读取有时不起作用?

    ios - 在iOS上链接libiconv

    objective-c - 如何关闭自动滑动返回导航 Controller ? swift

    ios - 将选定的单元格textLabel文本存储在数组中