Majster
Majster

Reputation: 3701

UITableViewCell view after being dequeued from UITableView not empty

I have a strange problem using the dequeueReusableCellWithIdentifier: method of UITableView. Not sure if I don't understand the method well enough or is it just plain weird. Here goes:

Im using a UITableView which presents some data to users, and inside my
- (UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath I use the dequeue method like so:

UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cell"];
    if (!cell)
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"cell"];

Afterwards I add some subviews to the contentView property of the cell. When scrolling a bit further down on my table I see those previously added subviews i.e. the cell is not empty but filled with "old" data. If I don't dequeue, and just alloc-init a new one each time, the cells are empty but I do see a bit more memory consumption which is precisely what Im trying to bring down a little. I'm using ARC if that means anything here.

What or how should I tackle the problem? I have tried running a for loop through the subviews of the content view and [view removeFromSuperview] which does remove the previous views and brings down memory consumption a little. But is that really necessary? Or is there a better way?

EDIT here is some more code how I add subviews

cell.backgroundView = [[UIView alloc] initWithFrame:cell.frame];
cell.backgroundColor = kClearColor; //defined to [UIColor clearColor]
cell.selectionStyle = UITableViewCellSelectionStyleNone;

if (indexPath.row == 0)
{
    UIImageView *shine = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 320, 50)];
    shine.image = [UIImage imageNamed:@"top_shine_1"];
    [cell.backgroundView addSubview:shine]; //its a gradient thats why its added to background

    UILabel *appLabel = [[UILabel alloc] initWithFrame:CGRectMake(55, winSize.height * 0.027, 250, 33)];
    appLabel.backgroundColor = kClearColor; //defined to clear color
    appLabel.textColor = kWhiteColor; //defined to white color
    appLabel.text = [viewOrder objectAtIndex:tableView.tag]; //just an array from where I get the required text
    appLabel.font = kStandardFontOfSize(30); //defined to a specific font

    [cell.contentView addSubview:appLabel];

    UIButton *settingsButton = [UIButton buttonWithType:UIButtonTypeCustom];
    settingsButton.frame = CGRectMake(10, winSize.height * 0.0377, 31, 21);
    [settingsButton setImage:[UIImage imageNamed:@"settings_button"] forState:UIControlStateNormal];
    [settingsButton addTarget:self action:@selector(settings:) forControlEvents:UIControlEventTouchUpInside];

    [cell.contentView addSubview:settingsButton];

    return cell; //here I just return it since this is all the config the first cell needs
}

NSString *app = [viewOrder objectAtIndex:tableView.tag];
NSArray *boxes = [[plist secondObjectForKey:@"order" parent:app] componentsSeparatedByString:@";"];

//Add necessary shines or create the last logotype cell - just some details and stuff, all are just images
if (indexPath.row == 1)
{
    UIImageView *shine = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 320, 282.5)];
    shine.image = [UIImage imageNamed:@"top_shine_2"];

    [cell.backgroundView addSubview:shine];
}
else if (indexPath.row == 2)
{
    UIImageView *shine = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, winSize.width, 150)];
    shine.image = [UIImage imageNamed:@"main_shine"];

    [cell.backgroundView addSubview:shine];
}
else if (indexPath.row == boxes.count + 1)
{
    UIImageView *logo = [[UIImageView alloc] initWithFrame:CGRectMake(111.5, 25, 97, 20)];
    logo.image = [UIImage imageNamed:@"cell_logo"];

    [cell.backgroundView addSubview:logo];
    return cell;
}

NSString *databox = [boxes objectAtIndex:indexPath.row - 1];
UIView *view; //Main subview to be added to the cell

/*
    here I have a class that creates a view with a bunch of subviews added to that view, the view is then assigned to 'view'; kinda like
view = [someAssembler assembleViewWith:options.....]. all are basically UILabels or ImageViews added to the main view
*/

[cell.contentView addSubview:view]; //and here this 'main view' is added as a subview, this view is still visible after the cell has been dequeued and the shines are as well

return cell;

Before you start criticising why im not using a single UIColor for background and text color let me remind you that this is still in testing stage, it will be taken care of later.

Upvotes: 0

Views: 929

Answers (1)

Eugene
Eugene

Reputation: 10045

[cell.backgroundView addSubview:shine]; these lines of code are the problem in your case.

You should create a complete reusable cell within the if (!cell) block and repopulate them each time cellForRow is being called. For every unique cell a unique reuse identifier should be used. For example, if you have multiple cells with differently laid out subviews, you should use different identifiers for them.

In your specific example cells must be created in the if (indexPath.row == 1) blocks.

static NSString *cellIdentifier = @"cell";
UITableViewCell *cell = nil;

if (indexPath.row == 0) {
  cellIdentifier = @"topCell";
  cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
  if (!cell) {
    // create the cell and add the necessary subviews for indexPath row 0
  }
  return cell;
}
else if (indexPath.row == 1) {

}

//etc.

}

You'll have to create the "main subview" for each cell in the !cell block with this approach though, so you should probably look into subclassing a cell.

Upvotes: 2

Related Questions