reloadRowsAtIndexPaths:withRowAnimation: 使我的应用程序崩溃
Posted
技术标签:
【中文标题】reloadRowsAtIndexPaths:withRowAnimation: 使我的应用程序崩溃【英文标题】:reloadRowsAtIndexPaths:withRowAnimation: crashes my app 【发布时间】: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:
消息时,它可以完美运行。
有什么想法吗?
【问题讨论】:
检查类似问题:***.com/questions/3542260/… 可能会有所帮助 【参考方案1】:问题是您可能更改了UITableView
数据源的项目数。例如,您在实现UITableViewDataSource
协议时使用的数组或字典中添加或删除了一些元素。
在这种情况下,当您调用reloadData
时,您的UITableView
会完全重新加载,包括部分数和行数。
但是当您调用reloadRowsAtIndexPaths:withRowAnimation:
时,这些参数不会重新加载。这导致了下一个问题:当您尝试重新加载某个单元格时,UITableView
检查数据源的大小并发现它已被更改。这会导致崩溃。只有当你想重新加载单元格的内容视图时(例如,标签已经改变或者你想改变它的大小),才可以使用此方法。
现在,如果您想从UITableView
中删除/添加单元格,您应该使用下一种方法:
-
通过调用方法
beginUpdates
通知UITableView
其大小将被改变。
通知使用方法- (void)insertRowsAtIndexPaths:(NSArray *)indexPaths withRowAnimation:(UITableViewRowAnimation)animation
插入新行。
通知使用方法- (void)deleteRowsAtIndexPaths:(NSArray *)indexPaths withRowAnimation:(UITableViewRowAnimation)animation
删除行。
通过调用方法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 会检查您的节数、每个节中的行数,然后重新加载整个内容。
【讨论】:
以上是关于reloadRowsAtIndexPaths:withRowAnimation: 使我的应用程序崩溃的主要内容,如果未能解决你的问题,请参考以下文章