40

Apple's documentation says of the indexPath parameter:

The index path specifying the location of the cell. The data source receives this information when it is asked for the cell and should just pass it along. This method uses the index path to perform additional configuration based on the cell’s position in the table view.

But register(Class|Nib):forCellReuseIdentifier: only specifies the reuse identifier to use, not the section or a set of index paths.

I thought perhaps UITableViewCell had some way of getting its hands on the index path, so it could, say, round its corners if in the first row of a section, but I'm not seeing it. At creation time, all it gets is its style and reuse identifier (initWithStyle:reuseIdentifier:); at reuse time, all it gets told is prepareForReuse.

Seeing as the old dequeueReusableCellWithIdentifier: is still supported, what sort of index-path-based configuration could it possibly be doing, if it can't rely on having the chance to do it, anyway?

I checked the Table View Programming Guide, but it hasn't been updated since iOS 5.

Jeremy W. Sherman
  • 35,901
  • 5
  • 77
  • 111
  • I would guess that the benefit is there for the tableView rather than the cell (it might allow it to choose which particular cell from the reuse pool to reuse?) but that is pure speculation. – jrturton Oct 03 '12 at 18:51
  • You should accept the answer from @svena (in my opinion). – matt Feb 10 '14 at 23:16
  • @matt Thank you for drawing my attention to svena's answer. You were correct, and I have accepted it as suggested. – Jeremy W. Sherman Feb 11 '14 at 16:05

4 Answers4

39

The most important difference between dequeueReusableCellWithIdentifier: and dequeueReusableCellWithIdentifier:indexPath: is that they are different methods! Thus they can behave differently, and they do. This has nothing to do with the indexPath, really; we just need a way to distinguish them.

The New Way

In particular, if you call dequeueReusableCellWithIdentifier:indexPath:, this is a sign that you are using the new iOS 6 register-and-dequeue system. So, if you have failed to register this identifier, you'll get a nice crash and a log message explaining the problem. This method will never return nil; it always returns a cell, either by creating a new one or by reusing one.

The Old Way

On the other hand, plain and simple dequeueReusableCellWithIdentifier: is old and has to be backward compatible. If you haven't registered this identifier, it won't complain: it will just return nil, leaving you high and dry. You'll have to create the cell yourself, as in the bad old days.

EDIT: But see also the answer by @svena! The new way (with indexPath:) has a second advantage I didn't know about: the cell is correctly sized at the time it is returned to you.

matt
  • 515,959
  • 87
  • 875
  • 1,141
  • Good point, except you're wrong about the old method. Apple docs state, "If you registered a class for the specified identifier and a new cell must be created, this method initializes the cell by calling its `initWithStyle:reuseIdentifier:` method. For nib-based cells, this method loads the cell object from the provided nib file. If an existing cell was available for reuse, this method calls the cell’s `prepareForReuse` method instead." So if it has a way to create the cell for you, whether by nib or class registration, it acts just like the new method. – Jeremy W. Sherman Nov 02 '12 at 17:02
  • The "throws on unregistered identifier" behavior of the new method is good information. It's something that *should* be in Apple's docs, but doesn't seem to be. – Jeremy W. Sherman Nov 02 '12 at 17:03
  • 1
    Unfortunately, none of this explains how "This [new] method uses the index path to perform additional configuration based on the cell’s position in the table view." A side helping of mystery "additional configuration" c/o Apple cafeteria… – Jeremy W. Sherman Nov 02 '12 at 17:04
  • It's not my job to justify Apple's docs. The "additional configuration" stuff could be totally bogus for all I know. What I'm explaining is why it can be important and useful to use the new call; its behavior _is_ definitely different from the old call, in what I have found to be a good way. – matt Nov 02 '12 at 18:32
  • 1
    No, it's not your job. But the question happens to be about that particular "additional configuration" detail of the docs, so that is the job of an answer to this question. – Jeremy W. Sherman Nov 02 '12 at 21:07
  • Okay, then my answer is that the documentation is probably bogus. Structurally, what I said is adequate: the extra parameter is merely to distinguish this method from the earlier method, and implies that there _must_ be a previous registration of the given identifier. – matt Nov 03 '12 at 00:58
  • @matt I do not agree that the method is merely for distinction. From layout perspective there is a rather big difference. – svena Apr 23 '13 at 17:34
  • @svena what is that difference? – matt Apr 23 '13 at 17:44
  • @matt The difference is that with -dequeueReusableCellWithIdentifier:forIndexPath: you have the cell frame (edit: actually bounds, not frame) set for you while with the old method you don't. – svena Apr 23 '13 at 20:58
  • @svena What do you mean "set for you"? I've been using "the old method" since iOS 3.2 and I've never had to set the cell size. It has *always* been "set for you". Its width is automatically the table width and its height is determined by `rowHeight` or `tableView:heightForRowAtIndexPath:`. Are you saying that with `dequeueReusableCellWithIdentifier:forIndexPath:` this happens *sooner*? – matt Apr 24 '13 at 00:00
  • 2
    @matt I'm saying that if you inspect cell.contentView.bounds returned by both methods. The version with indexPath as its argument, will return a cell that has the actual width and height already set (known) and you can make minor layout changes of the subviews in that contentView. – svena Apr 24 '13 at 09:03
  • @svena Right, so you *are* saying the bounds are set sooner. That's what I was asking. Thanks! (Upvoted your answer.) – matt Apr 24 '13 at 16:15
37

According to WWDC 2012 Session 200 - What's New In Cocoa Touch,

If you use - dequeueReusableCellWithIdentifier:forIndexPath: to dequeue your cell, it will be the right size and you'll be able to do layout inside your cell's contentView.

That's pretty much a quote from Chris Parker, a UIKit Engineer.

Up until iOS 6, you had to subclass your UITableViewCell and override - layoutSubviews if you wanted to make layout adjustments. From encapsulation point of view, this might still be the better solution – however, sometimes you just need a tiny adjustment, and now you can do that in - tableView:cellForRowAtIndexPath: instead.

Chris Nolet
  • 8,714
  • 7
  • 67
  • 92
svena
  • 2,769
  • 20
  • 25
  • 2
    Until iOS6, you had to subclass your UITableViewCell and override -layoutSubviews. From encapsulation point of view this might still be the better solution, however sometimes you just need a tiny adjustment and subclassing for only that might be well - heavy. – svena Apr 02 '13 at 16:13
2

I believe it is used to call the tableView:heightForRowAtIndexPath: method, if one exists, allowing the cell to be correctly sized.

idz
  • 12,825
  • 1
  • 29
  • 40
-2

I always thought that UIKit would round the corners of the top and bottom cells in a grouped table view when the UITableViewDelegate method:

- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath

is called. However, knowing the index path isn't much use unless the cell also knows how many rows are in the same section so it can work out if it's the last cell or not.

I assume that the addition of the index path to the method dequeueReusableCellWithIdentifier: is to improve performance perhaps as @jrturton suggested with different reuse pools or simply to determine the position of a cell in grouped sections.

As far as I can remember from the WWDC videos, there were a few additional methods added in iOS 6 to support reordering, insertion and deletion of cells so perhaps this also comes into factor here?

Zack Brown
  • 5,990
  • 2
  • 41
  • 54