reloadRowsAtIndexPaths:withRowAnimation:崩溃我的应用程序

时间:2010-12-16 13:57:39

标签: iphone uitableview crash

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

我的代码如下所示:

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

当我用简单的reloadRowsAtIndexPaths:withRowAnimation:替换reloadData消息时,它的效果非常好。

有什么想法吗?

8 个答案:

答案 0 :(得分:28)

问题是你可能已经改变了你的桌子的大小。例如,您已为表视图添加或删除某些源数据。

在这种情况下,当您致电reloadData时,您的工作表会完全重新加载,包括部分的大小和部分的数量。

但是,当您调用reloadRowsAtIndexPaths:withRowAnimation:时,表格视图的参数不会重新加载。这会导致下一个问题:当您尝试重新加载某些单元格表时,请检查表格视图的大小并看到它已被更改。这导致了崩溃。只有当您不想重新加载单元格视图时才能使用此方法(例如,标签已更改或您想要更改其大小)。

现在,如果要从/向表视图中删除/添加单元格,则应使用下一种方法:

  1. 通过调用beginUpdates
  2. 的方法UITableView通知表格,其大小将会改变
  3. 使用方法- (void)insertRowsAtIndexPaths:(NSArray *)indexPaths withRowAnimation:(UITableViewRowAnimation)animation
  4. 通知有关插入新行的信息
  5. 使用方法- (void)deleteRowsAtIndexPaths:(NSArray *)indexPaths withRowAnimation:(UITableViewRowAnimation)animation
  6. 通知删除行
  7. 通过调用endUpdates
  8. 的方法UITableView通知表格已更改其大小

    希望它会有所帮助

答案 1 :(得分:9)

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

[self.tableView beginUpdates];

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

[self.tableView endUpdates];

答案 2 :(得分:5)

我遇到了这个问题,这个问题是由一个调用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;
        }
    });
}

答案 3 :(得分:1)

这是旧的。不使用。 我在调用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];

答案 4 :(得分:1)

经过多次尝试,我发现“reloadRowsAtIndexPaths”只能在某些地方使用,如果只改变单元格内容而不是插入或删除单元格。没有任何地方可以使用它,即使你把它包装在

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

我发现可以使用它的地方是:

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

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

因此,请尝试仅在这些地方使用“reloadRowsAtIndexPaths”。

答案 5 :(得分:1)

您应该在重新加载前检查单元格可见性。这是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)
        }

答案 6 :(得分:0)

我有同样的问题。就我而言;只有当另一个视图控制器弹出/推过现有的表视图控制器然后调用[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 :(得分:0)

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

所以要么你只是删除了电话

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

或用

替换它
[self.tableView reloadData];

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