Jason Lee
Jason Lee

Reputation: 3250

cellForRowAtIndexPath isn't called after reloadRowsAtIndexPaths

As the Apple Doc said,

Reloading a row causes the table view to ask its data source for a new cell for that row.

I combine UITableView with NSFetchedResultsController:

- (void)controllerWillChangeContent:(NSFetchedResultsController *)controller
{
    if (self.tableView.isEditing) 
    {
        [self.tableView setEditing:NO animated:YES];
    }
    [self.tableView beginUpdates];
}

- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller
{
    [self.tableView endUpdates];

    [self updateTabItemBadge];
    [self.noDataView setHidden:![self isNoData]];

    WXINFO(@"controllerDidChangeContent");
}

Between the above two functions, I reload the target cell:

enter image description here

    case NSFetchedResultsChangeUpdate: {
        if (indexPath) {
            [tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationNone];
        }

enter image description here

I set a breakpoint at Line1563, to check that the reloadRowsAtIndexPaths has been called, but after that, - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath wasn't called.

So, my cell could not be updated.

Somebody can tell me why? Thanks.

Upvotes: 6

Views: 4867

Answers (4)

Michael Westbrooks II
Michael Westbrooks II

Reputation: 145

This is a work around I did, but it did the job.

 func tableView(_ tableView: UITableView, commit editingStyle:
    UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
        if editingStyle == UITableViewCellEditingStyle.delete {
            if itemDetailDict.count - 1 <= 0 {
                self.mainTable.beginUpdates()
                let cellOne = self.mainTable.cellForRow(at: indexPath)
                cellOne?.textLabel?.text = "There are no items."
                self.mainTable.reloadRows(at: [indexPath], with: .automatic)
                self.mainTable.endUpdates()
            } else {
                self.mainTable.beginUpdates()
                let removeKey = Array(itemDetailDict.keys)[indexPath.row]
                itemDetailDict.removeValue(forKey: removeKey)
                mainTable.deleteRows(at: [indexPath], with: .automatic)
                self.mainTable.endUpdates()
            }
        }
    }

Essentially on the delete row function I wanted the user to be able to delete the row, but when only one row remained, I wanted to show a default message in the cell of the tableview.

To do this, I updated the datasource, and when there was no more data in the dictionary, I updated the cell to display the text, reloaded the cell, then called endUpdating on my tableview.

I hope this helps.

Upvotes: 0

Scott
Scott

Reputation: 1550

The only reliable way I've found to do this is by using an animation other than none. If any other animation is specified, the reload happens correctly.

Upvotes: 0

anuragbh
anuragbh

Reputation: 593

Wrap it in:

[tableView beginUpdates];
[tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationNone];
[tableView endUpdates];

Upvotes: 1

Anand
Anand

Reputation: 31

Could you please check by reloading the tableview using [tableView reloadData]?

If you want only one row to be updated without reloading the table, please check the 'indexPath' type. It should be NSIndexPath.

Upvotes: 0

Related Questions