【问题标题】:reloadRowsAtIndexPaths:withRowAnimation: crashes my appreloadRowsAtIndexPaths:withRowAnimation: 使我的应用程序崩溃
【发布时间】:2011-05-26 13:53:27
【问题描述】:

我的 UITableView 出现了一个奇怪的问题:我使用 reloadRowsAtIndexPaths:withRowAnimation: 重新加载了一些特定的行,但应用程序崩溃并出现看似无关的异常:NSInternalInconsistencyException - 尝试删除的行多于部分中存在的行。 em>

我的代码如下:

[self.tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:[NSIndexPath indexPathForRow:0 inSection:0]] withRowAnimation:UITableViewRowAnimationFade];

当我用简单的reloadData 替换该reloadRowsAtIndexPaths:withRowAnimation: 消息时,它可以完美运行。

有什么想法吗?

【问题讨论】:

标签: iphone uitableview crash


【解决方案1】:

问题是您可能更改了UITableView 数据源的项目数。例如,您在实现UITableViewDataSource 协议时使用的数组或字典中添加或删除了一些元素。

在这种情况下,当您调用reloadData 时,您的UITableView 会完全重新加载,包括部分数和行数。

但是当您调用reloadRowsAtIndexPaths:withRowAnimation: 时,这些参数不会重新加载。这导致了下一个问题:当您尝试重新加载某个单元格时,UITableView 检查数据源的大小并发现它已被更改。这会导致崩溃。只有当你想重新加载单元格的内容视图时(例如,标签已经改变或者你想改变它的大小),才可以使用此方法。

现在,如果您想从UITableView 中删除/添加单元格,您应该使用下一种方法:

  1. 通过调用方法beginUpdates通知UITableView其大小将被改变。
  2. 通知使用方法- (void)insertRowsAtIndexPaths:(NSArray *)indexPaths withRowAnimation:(UITableViewRowAnimation)animation插入新行。
  3. 通知使用方法- (void)deleteRowsAtIndexPaths:(NSArray *)indexPaths withRowAnimation:(UITableViewRowAnimation)animation 删除行。
  4. 通过调用方法endUpdates,通知UITableView其大小已更改。

【讨论】:

  • 理论上说得通,但行不通。我正在尝试重新加载部分,但它仍然崩溃。我使用 UITableViewAutomaticDimension 的估计标题和单元格高度作为高度,这是一个要求。
  • @sheetal,如果您采用此答案中的方法,则不必调用 reloadRowsAtIndexPaths:withRowAnimation:。基本上在模型数据结构中添加一行(大多数情况下是一个数组)。然后调用 beginUpdate、insertRowsAtIndexPaths 和 endUpdates。
【解决方案2】:

我认为以下代码可能有效:

[self.tableView beginUpdates];

[self.tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:[NSIndexPath indexPathForRow:0 inSection:0]] withRowAnimation:UITableViewRowAnimationFade];

[self.tableView endUpdates];

【讨论】:

  • 这个解决了我的问题。我正在使用核心数据,并且我已将不同的提取请求传递给 resultfetchcontroller 并在提取完成后重新加载表。即使提取成功,应用程序也崩溃了.但是使用上述方法重新加载成功。
  • 不正确。如果只有一个 reloadRowsAtIndexPath,则不需要 beginUpdates/endUpdates,但如果这是尝试重新加载新添加的行,则永远不会修复崩溃。详情请查看 Nekto 的回答。
【解决方案3】:

我遇到了这个问题,这是由调用 reloadRowsAtIndexPaths:withRowAnimation: 的块和调用 reloadData 的并行线程引起的。 崩溃是由于 reloadRowsAtIndexPaths:withRowAnimation 找到了一个空表,即使我检查了 numberOfRowsInSection 和 numberOfSections。

我的态度是,我真的不在乎它是否会导致异常。作为应用程序的用户,我可以忍受视觉损坏而不是整个应用程序崩溃。

这是我的解决方案,我很乐意分享并欢迎建设性的批评。如果有更好的解决方案,我很想听听?

- (void) safeCellUpdate: (NSUInteger) section withRow : (NSUInteger) row {
    // It's important to invoke reloadRowsAtIndexPaths implementation on main thread, as it wont work on non-UI thread
    dispatch_async(dispatch_get_main_queue(), ^{
        NSUInteger lastSection = [self.tableView numberOfSections];
        if (lastSection == 0) {
            return;
        }
        lastSection -= 1;
        if (section > lastSection) {
            return;
        }
        NSUInteger lastRowNumber = [self.tableView numberOfRowsInSection:section];
        if (lastRowNumber == 0) {
            return;
        }
        lastRowNumber -= 1;
        if (row > lastRowNumber) {
            return;
        }
        NSIndexPath *indexPath = [NSIndexPath indexPathForRow:row inSection:section];
        @try {
            if ([[self.tableView indexPathsForVisibleRows] indexOfObject:indexPath] == NSNotFound) {
                // Cells not visible can be ignored
                return;
            }
            [self.tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationNone];
        }

        @catch ( NSException *e ) {
            // Don't really care if it doesn't work.
            // It's just to refresh the view and if an exception occurs it's most likely that that is what's happening in parallel.
            // Nothing needs done
            return;
        }
    });
}

【讨论】:

    【解决方案4】:

    经过多次尝试,我发现“reloadRowsAtIndexPaths”只能在某些地方使用,如果只更改单元格内容而不是插入或删除单元格。不是任何地方都可以用的,就算你把它包起来

    [self beginUpdates];
    //reloadRowsAtIndexPaths
    [self endUpdates];
    

    我发现可以使用的地方有:

    - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath - (IBAction) unwindToMealList: (UIStoryboardSegue *) sender

    任何从其他地方尝试,例如从“viewDidLoad”或“viewDidAppear”调用它,要么不会生效(对于已经加载的单元格,我的意思是,重新加载不会生效)或导致异常。

    所以尽量只在那些地方使用“reloadRowsAtIndexPaths”。

    【讨论】:

      【解决方案5】:

      您应该在重新加载之前检查单元格的可见性。这是 Swift 3 代码:

              let indexPath = IndexPath(row: offset, section: 0)
              let isVisible = tableView.indexPathsForVisibleRows?.contains{$0 == indexPath}
              if let v = isVisible, v == true {
                  tableView.reloadRows(at: [indexPath], with: .automatic)
              }
      

      【讨论】:

      • 遇到了完全相同的问题,这就是解决方案:如果 indexPath 不可见,我将改用 reloadData。
      【解决方案6】:

      我有同样的问题。就我而言;只有当另一个视图控制器弹出/推送到现有的表视图控制器然后调用 [self.tableView reloadRowsAtIndexPaths] 函数时才会发生这种情况。

      reloadRowsAtIndexPaths 调用隐藏/显示表视图中的不同行,该表视图具有 30 多个视觉复杂的行。当我尝试解决这个问题时,我发现如果我稍微滚动一下表格视图应用程序并没有崩溃。如果我不隐藏单元格(通过返回 0 作为高度),它也不会崩溃

      为了解决这个问题,我只是更改了“(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath”函数并返回至少 0.01 作为行高。

      - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
      {
      ....
      return rowModel.height + 0.01; // Add 0.01 to work around the crash issue.
      }
      

      它为我解决了这个问题。

      【讨论】:

        【解决方案7】:

        这是旧的。不使用。 我在调用reloadRowsAtIndexPaths... 以将单元格更改为包含UITextField 的编辑单元格时遇到了这个问题。该错误告诉我我正在删除表中的所有行。为了解决这个问题,我删除了:

        [self.tableView beginUpdates];
        NSArray *reloadIndexPath = [NSArray arrayWithObject:[NSIndexPath indexPathForRow:count inSection:section]];
        [self.tableView reloadRowsAtIndexPaths:reloadIndexPath withRowAnimation:UITableViewRowAnimationFade];  
        [self.tableView endUpdates];
        

        替换为

        [self.tableView reloadData];
        

        【讨论】:

          【解决方案8】:

          应用程序崩溃是因为您对 tableView 进行了一些更改。您已经向 tableView 添加或删除了一些行。因此,当视图控制器向您的模型控制器类询问数据时,indexPaths 中存在不匹配。由于 indexPaths 修改后发生了变化。

          所以要么你简单地删除调用

          [self.tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:[NSIndexPath indexPathForRow:0 inSection:0]] withRowAnimation:UITableViewRowAnimationFade];
          

          或替换为

          [self.tableView reloadData];
          

          调用 reloadData 会检查您的节数、每个节中的行数,然后重新加载整个内容。

          【讨论】:

            猜你喜欢
            • 2013-08-20
            • 2021-08-28
            • 2012-05-09
            • 2010-11-08
            • 2014-01-24
            • 1970-01-01
            • 2015-12-21
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多