Objective C UITableView - Table cells display wrong content after changing cell's height
Solution 1
This is the usual problem people have with table cell reuse.
this line tries to reuse a cell. this means if cell 0 moves off screen it will be reused as cell 5:
CustomCell *cell = (CustomCell *)[tableView dequeueReusableCellWithIdentifier:MyIdentifier];
if a cell could not be reused you are creating a new one:
if (cell == nil){
cell = [[[CustomCell alloc] initWithFrame:CGRectZero reuseIdentifier:MyIdentifier] autorelease];
and on the next line is your problem, you set up the cell only if a cell couldn't be reused. Which happens 5 times (for the cells that are visible when the table becomes visible).
But all the cells that your table wants to display afterwards will be reused cells that have already content.
// Set up the cell
/*...*/
but don't worry. this is very easy to fix. You have to separate the creation of your cell from its configuration. Just shift some code around like this:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *MyIdentifier = @"MyIdentifier";
CustomCell *cell = (CustomCell *)[tableView dequeueReusableCellWithIdentifier:MyIdentifier];
if (cell == nil){
cell = [[[CustomCell alloc] initWithFrame:CGRectZero reuseIdentifier:MyIdentifier] autorelease];
}
// whatever happened before. You have a valid cell at this point.
// Set up the cell
int storyIndex = indexPath.row;
//[cell setText:[[stories objectAtIndex: storyIndex] objectForKey: @"title"]];
//Story title
//cell.textLabel.text = [[stories objectAtIndex: storyIndex] objectForKey: @"title"];
//cell.textLabel.font = [UIFont boldSystemFontOfSize:14];
cell.lTitle.text = [[stories objectAtIndex: storyIndex] objectForKey: @"title"];
cell.lSummary.text = [[stories objectAtIndex: storyIndex] objectForKey: @"summary"];
cell.lDate.text = [[stories objectAtIndex: storyIndex] objectForKey: @"date"];
return cell;
}
EDIT: maybe I should read the question next time. But I guess I'm still 100% correct.
If i remove the tableView:heightForRowAtIndexPath: everything is just fine (except not having the cell size i want)
I think this is coincidence. How much cells do you have? I guess around 7 or 8? Everything is fine because all your cells are visible at the same time. So there is no need to reuse a cell, and they all have the content they should have.
Solution 2
Using [indexPath indexAtPosition…] is most likely your source of error—it's not getting your proper index path.
However, if you are creating a CustomCell (hopefully in IB?) then you should set the size of the cell in IB, and not do it in code.
Comments
-
CdB about 2 years
I'm trying to build an application in xcode, which -beside others- reads an rss feed and displays the posts. I'm new with objective-c and find it a bit hard sometimes.
I use an NSMutableArray for the retrieved stories(posts). Each story is represented by an NSMutableDictionary which contains the title, subject, date and link of the post. All these are displayed in a UITableView within a UIViewController. I have customized my own cell, so i can display multiple labels in them.
My problem is that if i use tableView:heightForRowAtIndexPath:, first 5 cells (that fit to screen) display ok, but if you scroll down, next cells appear to have the same contents with first 5(that is cells 0-4 display ok, cell 5 has contents of cell 0, cell 6 of cell 1 etc)! If i remove the tableView:heightForRowAtIndexPath: everything is just fine (except not having the cell size i want)
Here's about how the code looks:
// NavigationContentsViewController.h @interface NavigationContentsViewController : UIViewController <UITableViewDelegate, UITableViewDataSource> { UITableView *myTableView; IBOutlet UITableView * newsTable; UIActivityIndicatorView * activityIndicator; CGSize cellSize; NSXMLParser * rssParser; NSMutableArray * stories; NSMutableDictionary * item; // it parses through the document, from top to bottom... NSString * currentElement; NSMutableString * currentTitle, * currentDate, * currentSummary, * currentLink; } @property(nonatomic,retain)NSMutableArray *itemsList; @property(nonatomic,retain)UITableView *myTableView; - (void)parseXMLFileAtURL: (NSString *)URL;
.
//NavigationContentsViewController.m - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { // Configure the cell. static NSString *MyIdentifier = @"MyIdentifier"; CustomCell *cell = (CustomCell *)[tableView dequeueReusableCellWithIdentifier:MyIdentifier]; if (cell == nil){ cell = [[[CustomCell alloc] initWithFrame:CGRectZero reuseIdentifier:MyIdentifier] autorelease]; // Set up the cell int storyIndex = indexPath.row; //[cell setText:[[stories objectAtIndex: storyIndex] objectForKey: @"title"]]; //Story title //cell.textLabel.text = [[stories objectAtIndex: storyIndex] objectForKey: @"title"]; //cell.textLabel.font = [UIFont boldSystemFontOfSize:14]; cell.lTitle.text = [[stories objectAtIndex: storyIndex] objectForKey: @"title"]; cell.lSummary.text = [[stories objectAtIndex: storyIndex] objectForKey: @"summary"]; cell.lDate.text = [[stories objectAtIndex: storyIndex] objectForKey: @"date"]; return cell; } return cell; } - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { NSString *selectedCellItem = [NSString stringWithFormat:@"%d", indexPath.row]; TableViewController *fvController = [[TableViewController alloc] initWithNibName:@"TableViewController" bundle:[NSBundle mainBundle]]; fvController.selectedCellItem = selectedCellItem; [self.navigationController pushViewController:fvController animated:YES]; [fvController release]; fvController = nil; } -(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{ return 80; }
Any clues? [EDIT: changed int storyIndex = indexPath.row;]
-
CdB over 13 yearschanged the part using [indexPath indexAtPosition…] to int storyIndex = indexPath.row; but no changes happened. but i'm still curious, why changing the height has to do with cell contents, and if removing heightForRowAtIndexPath everything is just fine. I created the CustomCell in xcode and not in IB. Is there any other way that i can set the cells height (maeby in CustomCell.m) ?
-
FeifanZ over 13 yearsDid you create the CustomCell by subclassing UITableViewCell and adding labels with methods like initWithFrame:? In that case, set the size of the cell in CustomCell.m, because it's not changing.
-
CdB over 13 yearsindexPath.row works fine - as [indexPath indexAtPosition:[indexPath length] - 1] worked too. It's just the contents being wrong when changing height (even if i use indexPath.row) how can i set the size inside the CustomCell.m (which as u said is subclassing UITableViewCell)?
-
FeifanZ over 13 yearsSet its frame in the default init; or you can use a proper initWithFrame. Apple's official documentation is actually helpful here; scroll about a third of the way down to where it says "Customizing Cells": developer.apple.com/library/ios/#documentation/UserExperience/… Also see this tutorial for adding custom cells in IB: iphone.galloway.me.uk/iphone-sdktutorials/…
-
CdB over 13 yearsOh God!!! Everything is just like you described! Now it makes sense. Thanks for giving the solution, as well as explaining why it should be like this!
-
CdB over 13 years@Inspire48 Thanks for all your suggestions! All of your comments helped me understand a bit more the table/cells structure and properties. I searched the tutorials based on your comments and understood things a lot better :)
-
FeifanZ over 13 yearsYou're welcome! Sorry I didn't catch the actual issue—I'm too used to template code to have realized that in effect you just a had a brace too far down…