Take the 2-minute tour ×

I am having some trouble with UITableView's reloadData method. I have found that it only calls cellForRowAtIndexPath if there are new cells being added or taken away.

Example: I have five cells, each containing five strings. If I add a new cell and call reloadData, the table is updated and I see it. Yet if I go into one of the five cells, add a new string, then return and call reloadData, none of the table view's delegate methods is called.

My question: Is it possible to force the table view to completely reload the data in all of its visible cells?

share|improve this question
add comment

5 Answers

up vote 4 down vote accepted

I found the problem- I had my cell customization code in the if(cell == nil) block, so because the cells were being recycled, they weren't being changed. Taking my customization code out of that block fixed the problem.

share|improve this answer
You saved my hours of efforts. Thank you! I would not have guessed this stupid mistake :) –  Pruthvid Feb 8 '13 at 22:27
Glad my solution could help someone else! –  Rickay Feb 8 '13 at 23:54
add comment

Well, the table view's only going to call cellForRowAtIndexPath on the visible cells but if you do call reloadData it will do that so there's something else going on here and I'm not sure what it is.

share|improve this answer
In this case, all of the cells are visible. I know that the data source (in this example, NSUserDefaults) is being updated, so I'm not exactly sure why only the new cells are being updated. –  Rickay Jan 21 '12 at 18:35
Have you traced the calls to cellForRowAtIndexPath to prove it's not being called or are you just not seeing a visual change? If cellForRowAtIndexPath is not being called ... I don't know what's going on. At that point, I'd go one step back and trace the calls to numberOfRowsInSection. In any case, I can say that cellForRowAtIndexPath should be called for every visible cell when you do reloadData. –  smparkes Jan 21 '12 at 18:41
NSLogs say that when I add a new row, everything gets updated; my initial hypothesis was wrong. When calling reloadData upon return to the table view from another view controller, nothing is called. –  Rickay Jan 21 '12 at 18:59
Are you explicitly calling reloadData? It doesn't get called automatically just because the table view becomes visible again. –  smparkes Jan 21 '12 at 19:09
I know, and yes, I am –  Rickay Jan 21 '12 at 19:12
show 2 more comments

Even if your tableview has 50 rows, there only will exist as much cells as can be visible at one time. That's the whole story behind the reuseIdentifier. So forcing 'all the cells' doesn't exist. If a new cell appears, the data is loaded dynamically.

The only way to change a cell is to change the data that is delivered by the dataSource method cellForRowAtIndexPath.

share|improve this answer
I misspoke in my question; I have now updated it. –  Rickay Jan 21 '12 at 19:01
And if you try reloadRowsAtIndexPaths: withRowAnimation: Just to check... Not to let this be the solution. –  Jodocus Jan 21 '12 at 19:08
That also does not work; it has no effect. –  Rickay Jan 21 '12 at 19:26
Are you sure that the variable you are passing reloadData to isn't nil at that moment? –  Jodocus Jan 21 '12 at 20:57
add comment

Do not take your code out of the if (cell == nil) block. Instead, create a representative identifier for the cell you're making; try and make sure that all of the cell's content is referred to in the identifier. For example, if you have 3 numbers showing, make sure to have those three numbers in the identifier in a unique way that would only refer to a cell that has such content.

Let's say you have three NSArray properties in your class, array1, array2, and array3 that have int values wrapped inside of NSNumber objects. You want to use those NSArrays to fill a UITableView, this is what I'd do:

- (UITableViewCell *)tableView:(UITableView *)tableView 
                     cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    NSString *identifier = [NSString stringWithFormat:@"%@-%@-%@",
                            [[array1 objectAtIndex:indexPath.row] intValue],
                            [[array2 objectAtIndex:indexPath.row] intValue],
                            [[array3 objectAtIndex:indexPath.row] intValue]];
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier];

    if (cell == nil) {
        cell = [[[UITableViewCell alloc] 
                                  reuseIdentifier:identifier] autorelease];

        //Build your cell here.

    return cell;
share|improve this answer
add comment

I've found that reloading sections reloads data more readily. If you just have one section you can try:

[self.tableView reloadSections:[NSIndexSet indexSetWithIndex:0] withRowAnimation:UITableViewRowAnimationNone];

share|improve this answer
add comment

Your Answer


