Dan Rosenstark
Dan Rosenstark

Reputation: 69757

dequeueReusableCellWithIdentifier and then don't use the cell?

If I call:

-[UITableView dequeueReusableCellWithIdentifier]

and then I choose not to reuse the cell in this method

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath

is a leak necessarily introduced? My guess is that it would be dealloced as soon as the autorelease pool drains.

Upvotes: 1

Views: 2426

Answers (4)

Dan Rosenstark
Dan Rosenstark

Reputation: 69757

Yes, this introduces a leak. Try this empirically by subclassing UITableViewCell:

static int instances = 0;
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
    self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
    if (self) {
        NSLog(@"Init! instances=%d", instances++);
    }
    return self;
}

-(void)dealloc {
    NSLog(@"Dealloc! instances=%d", --instances);
}

If you don't use the cell that comes back from dequeueReusableCellWithIdentifier you will have a leak.

There are two solutions to this problem:

  1. Use the results of dequeueReusableCellWithIdentifier as you're supposed to or
  2. Use nil as the reuseIdentifier; then no leak will be introduced. This is the best solution unless your table has a lot of rows, and you don't want to deal with the mess of reuse.

Upvotes: 4

Leszek Szary
Leszek Szary

Reputation: 10336

If you do not return UITableViewCell returned by dequeueReusableCellWithIdentifier in - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath; then it might create a leak or not depending on what you are doing. Cells returned by dequeueReusableCellWithIdentifier are automatically released when table view is released because table view is holding a reference to every cell returned by this method.

You will have a problem if for example you call dequeueReusableCellWithIdentifier repeatedly in - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath like this:

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    CustomCell *cell = [tableView dequeueReusableCellWithIdentifier:@"CustomCell"];
    // calculate height
    // ...
}

In above code dequeueReusableCellWithIdentifier will always return new cell everytime this method is called so memory usage will rise when you scroll the table view. However at some later point in time these cells allocated by dequeueReusableCellWithIdentifier will be automatically released when table view is realeased.

Upvotes: 1

Matt
Matt

Reputation: 2411

No, this will not cause a leak, but will not necessarily be memory efficient either. If you wish to have all these cell reuse chores handled automatically for you, consider using a framework such as the excellent Sensible TableView (free).

Upvotes: 0

Martin R
Martin R

Reputation: 539775

Yes, dequeueReusableCellWithIdentifier returns an autoreleased object, and will not cause a memory leak.

But if you choose not to reuse cells (for whatever reason), then there is no need to call dequeueReusableCellWithIdentifier first.

Update: You can check how many cells are stored in the internal reuse queue with the following code:

NSDictionary *reuseDict = [self.tableView valueForKey:@"reusableTableCells"];
NSArray *reuseArray = [reuseDict objectForKey:CellIdentifier];
NSLog(@"%d", [reuseArray count]);

I tested this with the Master-Detail Xcode application, where I had removed the call to dequeueReusableCellWithIdentifier. The number of cells in the reuse queue increased to a maximum of 17 in landscape orientation and 23 in portrait. This was exactly the number of visible cells plus one. So the number is indeed limited, even if you never reuse cells.

Upvotes: 2

Related Questions