UITableView
iOS Development
Swift
dequeueReusableCellWithIdentifier
Programming Tips

When to use dequeueReusableCellWithIdentifier vs dequeueReusableCellWithIdentifier forIndexPath

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

These two dequeue APIs reflect two generations of table-view usage in UIKit. In modern iOS code, dequeueReusableCell(withIdentifier:for:) is the standard choice because it guarantees a cell when registration is set up correctly, while the older dequeueReusableCell(withIdentifier:) returns an optional and belongs mostly to legacy patterns.

The older API

The older method is:

swift
let cell = tableView.dequeueReusableCell(withIdentifier: "UserCell")

This may return nil if no reusable cell exists and no registration or storyboard prototype covers that identifier. Older code often looked like this:

swift
let cell = tableView.dequeueReusableCell(withIdentifier: "UserCell")
    ?? UITableViewCell(style: .subtitle, reuseIdentifier: "UserCell")

That was normal when cell creation was managed manually.

The modern API

The newer and preferred method is:

swift
let cell = tableView.dequeueReusableCell(withIdentifier: "UserCell", for: indexPath)

This method assumes you have already registered the cell class or nib, or provided a prototype cell in Interface Builder. If registration is correct, the method always returns a cell and does not require a nil check.

Typical setup:

swift
1override func viewDidLoad() {
2    super.viewDidLoad()
3    tableView.register(UITableViewCell.self, forCellReuseIdentifier: "UserCell")
4}

Then in cellForRowAt:

swift
1override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
2    let cell = tableView.dequeueReusableCell(withIdentifier: "UserCell", for: indexPath)
3    cell.textLabel?.text = "Row \(indexPath.row)"
4    return cell
5}

This is cleaner and matches how Apple expects table views to be configured in current UIKit code.

Why the for: version is better

Advantages of dequeueReusableCell(withIdentifier:for:):

  • no optional handling in normal use
  • cleaner cellForRowAt implementation
  • stronger alignment with registration-based cell setup
  • fewer hidden fallback creation paths

If registration is missing, it fails loudly, which is usually better than returning nil and hiding a setup mistake.

When the old method still appears

You still see dequeueReusableCell(withIdentifier:) in:

  • older Objective-C and Swift codebases
  • highly customized legacy table setup
  • code paths outside cellForRowAt where no index path is available

Even then, it is often a signal that the view code predates the more modern registration pattern.

UICollectionView follows the same direction

The same general idea exists for collection views. Modern UIKit encourages registration and index-path-based dequeuing because it makes reuse behavior more explicit and predictable.

That is why, in current code, the question is usually not "which one should I prefer," but "is there a specific legacy reason I still need the old one."

If there is no such reason, the for: variant should usually be your default starting point.

Common Pitfalls

The most common mistake is using dequeueReusableCell(withIdentifier:for:) without registering the cell class, nib, or storyboard prototype first. Another is continuing to use the old optional-returning method in new code simply out of habit from older tutorials. Developers also sometimes create fallback cells manually while also trying to use registration-based reuse, which mixes two patterns unnecessarily. Confusion can also arise when the older method is called outside cellForRowAt, because the lack of an index path changes what the API can guarantee. Finally, people often focus on dequeuing method choice while forgetting the more important requirement: reset reused cell state correctly during configuration.

Summary

  • In modern UIKit, prefer dequeueReusableCell(withIdentifier:for:).
  • The for: version assumes proper registration and returns a non-optional cell.
  • The older dequeueReusableCell(withIdentifier:) mainly survives in legacy or specialized code.
  • Registration setup is the key requirement for the newer API to work correctly.
  • Use one reuse pattern consistently instead of mixing manual creation with registered dequeuing.
  • Focus on correct cell configuration after dequeuing, because reuse bugs often come from stale state rather than the dequeue call itself.

Course illustration
Course illustration

All Rights Reserved.