Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Understanding UITableView dequeueReusableCellWithIdentifier - returns cell even on the first call

I'm having trouble understanding how this works. I've read many threads on SO about it - such as UITableView dequeueReusableCellWithIdentifier Theory and How does dequeueReusableCellWithIdentifier: work?.

However, my UITableView succesfully dequeues a cell each time (it's never nil), even when it first loads. I was under the impression that similar cells should use the same identifier, so you only have to change what's necessary.

Because

if (!cell) {
    NSLog(@"New cell");
    cell = [[UITableViewCell alloc] initWithStyle:someStyle reuseIdentifier:someIdentifier];
}

Never gets called, I'm not sure how I'm supposed to handle cells in the same table with different styles, because the style can only be set in the initializer.

I also tried using different cell identifiers, to make sure it wasn't reusing cells from a different table or something. I am registering these identifiers with [tableView registerClass: forCellReuseIdentifier:]

If I understand, this method should only return previously created cells that have been moved off the screen (hidden, i.e. can be reused). Then how come it returns a cell the first time it's called?


Edit: So the confusion was using [tableView dequeueReusableCellWithIdentifier: forIndexPath:] instead of [tableView dequeueReusableCellWithIdentifier:] (the first requires registering the identifier, the second will return nil if none is available - the behavior I was expecting above).

However, I noticed that when I changed my code to use [tableView dequeueReusableCellWithIdentifier:], it creates a new cell, and its contentView.frame has a width of 320 (full width). Before, when I did dequeue...forIndexPath it would give a width of 302, or the visual/"real" width of the cell. Why is this?

Also, is there a way to specify the style of the UITableViewCells regstiered for reuse?


Solution: So I found this thread UITableView cell.contentView.bounds.size.width Changes With Cell Reuse, which says when you set the autoresizingmask to UIViewAutoresizingFlexibleLeftMargin, it's fixed when you try to do relative positioning (the contentView width is initially the fully width, but when you present it it's shrunk, so if you do your calculations right it'll still show up properly).

I was positioning a UISwitch on the right - and when I set the autoresizing mask it works when it's first displayed but shifted over another ~20 pixels when I switched it. I don't know what caused that extra shift, but I ended up solving it by simply setting the UISwitch as the cell's accessoryView.

(This is partially off topic from the original question, but if someone stumbles on this maybe it'd be useful). For anyone wondering specifically about the original question, the answer is under the first edit.

like image 362
Raekye Avatar asked Jun 18 '13 19:06

Raekye


1 Answers

When you call [tableView registerClass: forCellReuseIdentifier:], you're teaching the table view what to do when you later use the specified ReuseIdentifier. So, when you later call [tableView dequeueReusableCellWithIdentifier:] it will either:

A. Get a cell that has previously been created and isn't currently being used

OR

B. Create a new cell of the class you specified

So, when you dequeue, you will always get an instance. If you want to create new cell instances yourself with initWithStyle:reuseIdentifier: then you shouldn't register a class with the table view. Alternatively, leave the registration and add logic to specify everything that needs to be configured (and consider using multiple different cell classes and reuse identifiers).

like image 144
Wain Avatar answered Nov 15 '22 17:11

Wain