UITableView insertRowsAtIndexPaths 抛出 __NSArrayM insertObject:atIndex:'object cannot be nil' 错误

Posted

技术标签:

【中文标题】UITableView insertRowsAtIndexPaths 抛出 __NSArrayM insertObject:atIndex:\'object cannot be nil\' 错误【英文标题】:UITableView insertRowsAtIndexPaths throwing __NSArrayM insertObject:atIndex:'object cannot be nil' errorUITableView insertRowsAtIndexPaths 抛出 __NSArrayM insertObject:atIndex:'object cannot be nil' 错误 【发布时间】:2014-03-05 17:47:59 【问题描述】:

我正在尝试将项目动态插入到我的表格视图中。我的应用程序有一个聊天部分,它在第 0 部分显示旧的(在初始化视图控制器之前从服务器加载)消息,并在第 1 部分显示刚刚发送/接收的消息(最初为零)。加载视图时,所有“旧”消息都已加载并显示,没有问题。当我尝试插入行时,问题就开始了。这是我正在做的事情:

我首先通过添加一个额外项来更新我的表格视图的数据源:[newMessages addObject:newMessage];(newMessage 是我的自定义消息对象的一个​​实例,newMessages 是我的数据源)。我验证我的数据源现在有 1 项(添加前为 0)。

然后我调用以下代码:

[self.chatTableView beginUpdates];
[self.chatTableView insertRowsAtIndexPaths:@[[NSIndexPath 
    indexPathForRow:newMessages.count - 1 inSection:1]] 
    withRowAnimation:UITableViewRowAnimationBottom];
[self.chatTableView endUpdates];

我的应用程序在 endUpdates 方法处崩溃,给我这个错误:*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[__NSArrayM insertObject:atIndex:]: object cannot be nil'

我立即检查了newMessage 是否为nil,它不是 nil(并重新检查了我的数据源)所以数据源不是问题。我认为indexPathForRow:newMessages.count - 1 可能是问题所在,并尝试了不同的值(count - 2、count、count + 1),以防万一我遗漏了什么。在这些情况下,我收到另一个错误:'NSInternalInconsistencyException', reason: 'attempt to insert row 1 into section 1, but there are only 1 rows in section 1 after the update'。错误说明了一切,所以问题也不在于indexPathForRow:newMessages.count - 1

我在-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 方法中添加了断点,以查看它何时被准确调用以及返回什么。似乎根本没有调用该方法,断点没有命中(它确实在第一次加载视图并正确加载初始数据时命中,并且我没有在任何地方设置数据源,因此委托/数据源也已连接正确)。我立即检查了其他方法:

-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
    return 2;


-(NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
    if(section == 0)
        return @"Eski mesajlar";
    else
        return @"Yeni mesajlar";
    

这些方法返回正确的值。我在-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView 中放置了一个断点,以查看它何时被调用。它显然 [self.chatTableView endUpdates]; 方法内调用的(从线程/队列的调用堆栈中可以看出),但随后 [self.chatTableView endUpdates]; 立即抛出错误,甚至没有进入 -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 方法。我见过一些例子(以及其他一些例子),例如:

how to properly use insertRowsAtIndexPaths? Error creating row in tableview Add cell to bottom of UITableView in ios Tableview crashes when moving more than half the cells to another section

我已经阅读了那里的答案,但没有一个对我有帮助。我做错了什么?

【问题讨论】:

【参考方案1】:

您是否实施了tableView:estimatedHeightForRowAtIndexPath:?我在我自己的一个使用NSFetchedResultsController 的应用程序中注意到了一个类似的问题,当调用tableView:endUpdates 时,应用程序会崩溃并显示相同的错误消息。注释掉 tableView:estimatedHeightForRowAtIndexPath: 为我修复了它。

【讨论】:

没错。我有那个方法,并评论它解决了这个问题。谢谢,我可能永远也想不通,我会向 Apple 提交错误报告。 我没有使用获取的结果控制器,而是基于网络数据,我可以确认注释掉估计的高度部分也阻止了我的崩溃。 这个答案救了我的命!解决了崩溃并使插入动画更加流畅!谢谢! 当您删除tableView:estimatedHeightForRowAtIndexPath: 方法(或停止使用estimatedRowHeight 属性)时,请确保您完全了解自己在做什么。您现在强制表格视图为表格视图中的 每一 行调用 tableView:heightForRowAtIndexPath:,然后在每次调用 reloadData 或类似内容时显示任何内容 - - 主要的性能影响!因此,删除行高估计的使用并不是一个真正的修复,只是一个似乎是 Apple 错误的解决方法。 (@CanPoyrazoğlu 你有你提交的错误的雷达吗?) 我认为这个“错误”没有完全解决,因为我遇到了相同的崩溃/异常问题并注释掉 tableView:estimatedHeightForRowAtIndexPath: 使它消失(但使 tableView 滚动生涩且无法使用.)【参考方案2】:

关于删除/注释掉 tableView:estimatedHeightForRowAtIndexPath:,这不是我解决它的方法,因为我的委托没有那个方法。

相反,我实际上在我的viewDidLoad 中设置了tableView.estimatedSectionHeaderHeight = 10.;。通过简单地注释该行,异常不再发生,然后按我的预期工作。

不过,这太糟糕了,因为我无法说明为什么将其注释掉(或 estimatedHeightForRowAtIndexPath: 方法)会修复它。

【讨论】:

这对我有帮助,删除了任何 tableView.estimatedSectionHeaderHeighttableView.sectionHeaderHeight 呼叫为我解决了这个问题。这不是他们第一次给我带来麻烦了……我只是从现在开始假装他们不存在,因为他们只会破坏东西…… 这也为我解决了这个问题,在 iOS 9.2 上(!) 亲爱的主,这也帮助了我!感谢您现有的@speby!我不得不保留rowHeight = UITableViewAutomaticDimension tho,否则它仍然会失败。 不客气@Gee.E!很高兴我能帮上忙。这是一段时间的实时接收器!【参考方案3】:

我最近解决了这个问题,但没有注释掉 estimatedHeightForRowAtIndexPath:。我遇到的具体问题是我们的表格有许多不同大小的单元格,所以我们只是在估计中使用了平均大小。修复是为了更好地估计插入单元格的大小。

我的假设是该错误是由表格试图滚动到插入的单元格引起的。显然,当滚动到高度估计过小的插入单元格时,先前估计的 contentSize 会导致问题。

【讨论】:

【参考方案4】:

我遇到了这个问题,并通过在表为空时不插入来解决它。换句话说,如果表没有行,则不要使用insertRowAtIndexPaths。而是将对象添加到您的数组或任何数据源,然后调用[myTableView reloadData]

【讨论】:

【参考方案5】:

我相信您的错误在于 tableView:numberOfRowsInSection: 方法。 insertRowsAtIndexPaths 方法会在调用tableView:cellForRowAtIndexPath 之前调用此方法,并且它与数据源不匹配,可能是问题所在。

我看到newMessages 是一个局部变量,所以它可能不同步到从tableView:numberOfRowsInSection: 方法返回的数组。

要解决此问题,只需确保 tableView:numberOfRowsInSection 在更新时返回正确的数字即可。

另外:即使 newMessages 为 nil,count 方法也会返回 0 - Objective-C 就是这样工作的。

【讨论】:

以上是关于UITableView insertRowsAtIndexPaths 抛出 __NSArrayM insertObject:atIndex:'object cannot be nil' 错误的主要内容,如果未能解决你的问题,请参考以下文章

UItableview 单元格的动态高度与 UItableview 单元格内的 UItableview

UITableView

水平 UITableView 中的垂直 UITableView

如何与重叠显示的 UITableView 交互另一个 UITableView

在 UITableView 中的 UINib 中重新加载 UITableView

iOS小技能:1. 什么是UITableView? 2. UITableView如何展示数据