Objective C UITableView - Table cells display wron

2019-05-08 07:06发布

问题:

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

回答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.



回答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.