【问题标题】:iOS UITableview delete row with animationiOS UITableview删除带有动画的行
【发布时间】:2014-09-12 08:55:20
【问题描述】:

我看到了很多关于它的问题,但没有找到解决问题的方法。

我有一个带有自定义单元格的表格视图。在每个单元格中,我都有一个计时器。当时间到时,我发送一条消息删除该行(这不是我唯一使用接收消息的地方)。

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

- (void) timesup:(NSNotification *)notification{
    Data *data = notification.userInfo[@"data"];
    NSUInteger index = [datas indexOfObject:data];
    NSArray *deleteIndexPaths = [[NSArray alloc] initWithObjects:
                                 [NSIndexPath indexPathForRow:index inSection:0],
                                 nil];
    [datas removeObjectAtIndex:index];
    [self.tableView deleteRowsAtIndexPaths:deleteIndexPaths withRowAnimation:UITableViewRowAnimationFade];
}

- (NSInteger)tableView:(UITableView *)theTableView numberOfRowsInSection:(NSInteger)section
{
    if(datas.count > 0){
        return datas.count;
    }

    // Display a message when the table is empty
    UILabel *messageLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, self.view.bounds.size.width, self.view.bounds.size.height)];

    messageLabel.text = @"No data, pull to refresh";
    messageLabel.textColor = [UIColor blackColor];
    messageLabel.numberOfLines = 0;
    messageLabel.textAlignment = NSTextAlignmentCenter;
    [messageLabel sizeToFit];

    self.tableView.backgroundView = messageLabel;
    self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
    return 0;
}

我收到了这个错误(取决于我在玩应用程序时有多少数据):

无效更新:第 0 节中的行数无效。更新后现有节中包含的行数 (4) 必须等于更新前该节中包含的行数 (6),加上或减去从该节插入或删除的行数(0 插入,1 删除)加上或减去移入或移出该节的行数(0 移入,0 移出)。

当我有很多数据超时时发生错误。

注意:如果我不使用“deleteRowsAtIndexPaths”,只需从数据中删除并重新加载表即可完美运行

【问题讨论】:

  • 尝试使用异步串行队列来转移删除逻辑(在您的通知方法中)。这样,删除将按 FIFO 顺序进行序列化。或者更好地检查我在下面给出的代码。
  • 要显示的任何代码(一周前开始 iOS 开发:D)
  • 建议使用beginUpdatesendUpdates。此外,请确保删除后的行/节数等于数据源数组中的项目数。

标签: ios objective-c uitableview


【解决方案1】:

昨天我解决了您在 N.B. 中写的类似问题。以您建议的相同方式。我相信当表数据源混淆时会出现这个问题。为了克服这种情况,一种可能的解决方案是为删除行实施正确的流程。

BOOL isDeleteInProgress;

步骤:

  • 当您的计时器事件触发(调用)时,将 isDeleteInProgress 设置为 YES。
  • 如果由于另一个计时器再次调用它,则检查 isDeleteInProgress 是否为 NO 然后仅设置为 YES
  • 现在写下面的代码来删除行

    [self.tableView beginUpdates];

    [self.tableView deleteRowsAtIndexPaths:deleteIndexPaths withRowAnimation:UITableViewRowAnimationFade];

    [self.tableView endUpdates];

  • 一旦行删除成功,将 isDeleteInProgress 设置为 NO。

这将阻止持续调用删除,并可能阻止您出现此(未解决的)异常。

我已阅读您的评论(任何要显示的代码(一周前开始 iOS 开发:D))所以我添加一个可能对您有帮助的伪代码。

- (void)timerEventFire:(NSTimer*)timer {
    if(!isDeleteInProgress) {
        //write code to delete the rows
        //invalidate timer
        //isDeleteInProgress = NO;
    }
}

祝你好运!

【讨论】:

  • 看起来是一个很好的解决方法,但是您如何管理未删除的行,因为删除已经在进行中?
  • @Titmael,我们不必担心未删除的行,这将由数据源自行管理。
【解决方案2】:

执行以下操作:
1。向您的类接口添加一个变量: dispatch_queue_t _deleteQeue;
2。在您的viewDidLoad 中初始化队列:
_deleteQeue = dispatch_queue_create("com.delte.qeue", NULL);
3. 最后将你的方法的实现改成如下所示:

dispatch_sync(_deleteQeue, ^{
    //your deletion code that you have implemented. Deletion from datasource array
    dispatch_async(dispatch_get_main_queue(), ^{
        //cell delete code here. The table animation code. with begin and end updates.
    });
});

****编辑***
让我们试试这个

@synchronized (self) {
    // your deletion code with begin and end updates for the table. Throw away the dispatch code, go back to the old code with Begin and end updates and apply lock. like this.
}

【讨论】:

  • 我明白了,当同时删除多个数据时,您的方法会在删除表格单元格的动画进行时从数组中删除多个数据。因此问题。猜你将不得不使用序列化队列。
  • 还是同样的问题 :( 我在第一次调度中从数据中删除了数据,在第二次调度中我调用了被 beingUpdates 和 endUpdates 包围的单元格删除
  • 我已将第一个调度更改为同步运行..试试看。
  • 我猜UI更新应该在队列为空并且在队列中有东西进入之前执行
  • 是的..您需要这样做,以便在某个时间从数组和一个单元格中删除一项,直到单元格删除完成,我们不会从数组中删除另一项。我想我们应该加个锁看看。