UITableView insertRowsAtIndexPaths throwing __NSArrayM insertObject:atIndex:'object cannot be nil' error

无人久伴 提交于 2019-12-29 18:50:09

问题


I am trying to insert an item to my table view dynamically. My app has a chat section, where it displays the old (loaded from server before initializing the view controller) messages in section 0, and displays just sent/received messages (where it is initially zero) in section 1. When the view is loaded, all the "old" messages are loaded and displayed, no problem is there. The problem starts when I try to insert rows. Here is what I am doing:

  • I am first updating my table view's data source by adding an extra item: [newMessages addObject:newMessage]; (newMessage is an instance of my custom message object, and newMessages is my data source). I verify that my data source now has 1 item (which was 0 before adding).
  • I then call the following code:

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

My app crashes at endUpdates method, giving me this error: *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[__NSArrayM insertObject:atIndex:]: object cannot be nil'

I've immediately checked if newMessage is nil or not, it's not nil (and re-checked my data source) so data source is not the problem. I've thought that indexPathForRow:newMessages.count - 1 could be the problem and tried different values (count - 2, count, count + 1) just in case I was missing something. In those cases, I'm getting another error: 'NSInternalInconsistencyException', reason: 'attempt to insert row 1 into section 1, but there are only 1 rows in section 1 after the update'. The error says it all, so the problem is not something with indexPathForRow:newMessages.count - 1 either.

I've added breakpoints into the -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath method to see when it's exactly called and what it returns. It seems that the method is not called at all, the breakpoint is not hitting (it DOES hit when view is first loaded and loads the initial data correctly, and I'm not setting data source anywhere, so delegates/data sources are also connected correctly). Immediately I've checked other methods:

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

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

Those methods return correct values. I've put a breakpoint in -(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView to see when it's called. It apparently is called inside the [self.chatTableView endUpdates]; method (as seen from the thread/queue's call stack), but then [self.chatTableView endUpdates]; immediately throws the error without even entering -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath method. I've seen examples (and a few others) such as:

  • 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

I've read the answers there, but none of them helped me. What am I doing wrong?


回答1:


Do you have tableView:estimatedHeightForRowAtIndexPath: implemented? I've noticed a similar issue inside one of my own applications that used an NSFetchedResultsController where the application would crash with the same error message when tableView:endUpdates was called. Commenting out tableView:estimatedHeightForRowAtIndexPath: fixed it for me.




回答2:


Regarding removing/commenting out tableView:estimatedHeightForRowAtIndexPath:, that was not how I resolved it since I did not have that method on my delegate.

Instead, I had actually set tableView.estimatedSectionHeaderHeight = 10.; in my viewDidLoad. Turns out by simply commenting that line out, the exception no longer occurs and this then works as I expect it to.

It's too bad, though, because I can't say why commenting this out (or the estimatedHeightForRowAtIndexPath: method) fixes it.




回答3:


I recently resolved this issue without commenting out estimatedHeightForRowAtIndexPath:. The specific issue I had was that our table had many cells with different sizes and so we were simply using the average size in the estimation. The fix was to better estimate the size of the inserted cells.

My assumption is that the bug is caused by the table attempting to scroll to the inserted cell. Apparently the previously estimated contentSize causes issues when scrolling to inserted cells with heights that were estimated too small.




回答4:


I had this problem and fixed it by not inserting if the table is empty. In other words if the table has no rows then don't use insertRowAtIndexPaths. Instead add the object to your array or whatever data source and then call [myTableView reloadData]




回答5:


I believe your error is in the tableView:numberOfRowsInSection: method. The insertRowsAtIndexPaths method will call this method before calling tableView:cellForRowAtIndexPath and it this doesn't match to the data source, it could be the problem.

I see that newMessages is a local variable, so that way it is probably not synchronised to the array that returns from tableView:numberOfRowsInSection: method.

To fix the problem, just make sure the tableView:numberOfRowsInSection returns the correct number when doing the updates.

In addition: even if newMessages was nil, the count method would return 0 - Objective-C works that way.



来源:https://stackoverflow.com/questions/22205247/uitableview-insertrowsatindexpaths-throwing-nsarraym-insertobjectatindexobj

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!