iOS: Using the Wrong dequeueReusableCellWithIdentifier!

For dequeuing table view cells, I’ve been using the dequeueReusableCellWithIdentifier: method for a while now. I guess it just auto-completed for me one time in Objective-C and, since it was shorter than the other auto-completed method – dequeueReusableCellWithIdentifier:forIndexPath:, I just kept using it without thinking much about it.

This presented a problem for me in Swift with optionals:

    override func tableView(tableView: UITableView,
        cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
    {
        if let cell = tableView.dequeueReusableCellWithIdentifier("reuseIdentifier") {
             // Configure the cell...
            return cell
        }

        return UITableViewCell()
    }

As you can see, when you use dequeueReusableCellWithIdentifier:, it returns an optional. This means you have to unwrap it and handle the case where it doesn’t exist by returning an empty UITableViewCell(), which I’m pretty sure would just crash your app if it ever got to that point. But, that’s the only “clean” solution I could come up with.

However, yesterday @allonsykraken pointed out to me that all I had to do was look at the method signatures for the two dequeuing methods!

func dequeueReusableCellWithIdentifier(identifier: String) 
    -> UITableViewCell?

func dequeueReusableCellWithIdentifier(identifier: String,
    forIndexPath indexPath: NSIndexPath) 
    -> UITableViewCell

As you can see, dequeueReusableCellWithIdentifier:forIndexPath returns an actual UITableViewCell, not an optional one! If you read the comment in the source code, it explains this a bit more:

func dequeueReusableCellWithIdentifier(identifier: String) 
    -> UITableViewCell?
// Used by the delegate to acquire an already allocated cell, 
// in lieu of allocating a new one.
    
func dequeueReusableCellWithIdentifier(identifier: String,
    forIndexPath indexPath: NSIndexPath)
    -> UITableViewCell
// newer dequeue method guarantees a cell is 
// returned and resized properly, 
// assuming identifier is registered

So just by using the correct dequeueReusableCellWithIdentifier method, my optional issue is easily solved!

    override func tableView(tableView: UITableView,
        cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
    {
        let cell = tableView.dequeueReusableCellWithIdentifier("reuseIdentifier",
            forIndexPath: indexPath)

        return cell
    }

This is a good reminder to read documentation when things don’t work as they should! Thanks again @allonsykraken for pointing this out!

Enjoy the article? Join over 17,500+ Swift developers and enthusiasts who get my weekly updates.

  • Herbert

    In the first shorter case you check for it and if no cell is returned you create one in the code. The second method with indexPath requires a prototype cell created in your storyboard.

  • Garric G. Nahapetian

    I just ran into this problem last night. Will try this method soon. Thank you!

  • Eli Wang

    This is not correct. -[UITableView dequeueReusableCellWithIdentifier] does return an optional but it does create a new cell if you register a class or a nib. The version with ‘forIndexPath’ is explained here: http://stackoverflow.com/questions/12714737/where-does-the-indexpath-of-dequeuereusablecellwithidentifierforindexpath-get

  • I wouldn’t say tableView(_:dequeueReusableCellWithIdentifier:) is the “wrong” method, but rather, the right one for a different situation.

    If you are programmatically customizing cells based on their index path, it’s the way to go, giving you the opportunity to perform that customization the first time you create the cell (in response to dequeue returning nil). Example:

    However, if you’re using a prototype defined in a storyboard, then the tableView(_:dequeueReusableCellWithIdentifier:forIndexPath:) seems the right way to go. Note for this method, Apple warns: “You must register a class or nib file using the registerNib:forCellReuseIdentifier: or registerClass:forCellReuseIdentifier: method before calling this method.”

    Note also that in Apple’s TVPG, they use the first method in all their examples save the last, and that one with no comment.

  • Anirudha Mahale

    if you use “if let cell = tableView.dequeueReusableCellWithIdentifier(“reuseIdentifier”) {
    // Configure the cell…
    return cell
    }”
    you will get cell as optional only, better use it like this ”
    let cell = tableView.dequeReusableCellWithIdentifier(“cell”) as! UITableViewCell
    cell.label.text = “”
    return cell

  • Kriviq

    I have strong feelings against the “// assuming identifier is registered” part. The old method is pretty clear in it’s outcome, if it returns nil you could do something about it, whilst the second one just crashes if you don’t have cell registered for given identifier. I agree it makes for a shorter more concise code, but it comes at a cost.

  • Thibaut Noah

    Good article, i’m curious though, what about the case when you subclass UITableViewCell, you will still need to cast it and have no choice but to unwrap the optional.
    Is there a trick aswell?