在commitEditingStyle

时间:2017-11-06 23:06:16

标签: ios objective-c uitableview asynchronous ios11

模型是否会更改,行动画必须直接从commitEditingStyle启动,还是可以在以后的运行循环迭代中完成?

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

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


第一张图片显示了它在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


以下是用于测试它的表视图控制器的完整代码:

#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



更新
将此方法添加到表视图控制器可以修复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;
}

1 个答案:

答案 0 :(得分:2)

似乎在iOS 11中对UITableview进行了更改。

Apple的Build版本说明:

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

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

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

有了这个说法,有一个answer包含Apple开发论坛上一个问题所需的代码,可以解决一个非常相似的问题。

回答您的实际问题:

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

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

在查看评论中的详细信息后,我添加了一个链接(上图),这是Apple提供的最新“表格视图编程指南”。本指南中包含您已添加到问题中的详细信息的部分将会引导您或此问题的任何其他人。

还有一个方便的注释,其中包括如果必须在deleteRowAtIndexPath方法中进行commitEditingStyle调用。