7

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?

eric.mitchell
  • 8,817
  • 12
  • 54
  • 92

6 Answers6

10

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.

eric.mitchell
  • 8,817
  • 12
  • 54
  • 92
3

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];

jclv
  • 161
  • 1
  • 3
2

You can try this

[tableView reloadData];

or

[tableView deleteRowsAtIndexPaths:[NSMutableArray arrayWithObjects:indexPath, nil] withRowAnimation:UITableViewRowAnimationFade];

put this in commitEditingStyle method.

Gangani Roshan
  • 583
  • 1
  • 8
  • 25
0

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] 
                                  initWithStyle:UITableViewCellStyleDefault
                                  reuseIdentifier:identifier] autorelease];

        //Build your cell here.
    }

    return cell;
}
Mou Janki
  • 1
  • 1
0

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.

smparkes
  • 13,807
  • 4
  • 36
  • 61
  • 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. – eric.mitchell 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. – eric.mitchell 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
  • Yeah, I don't really know at this point. I'd suspect something in your program since the behavior doesn't sound right but until you find out what's causing the issue, who knows, could be an Apple bug. Unlikely, but not impossible. – smparkes Jan 21 '12 at 19:15
  • Very frustrating. Thank you for your efforts. – eric.mitchell Jan 21 '12 at 19:17
0

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.

Jodocus
  • 151
  • 6
  • And if you try `reloadRowsAtIndexPaths: withRowAnimation:` Just to check... Not to let this be the solution. – Jodocus Jan 21 '12 at 19:08
  • Are you sure that the variable you are passing `reloadData` to isn't nil at that moment? – Jodocus Jan 21 '12 at 20:57