Swift
iOS
UITableView
CustomCell
Programming Error

Could not cast value of type 'UITableViewCell' to 'AppName.CustomCellName'

Master System Design with Codemia

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

Introduction

This crash appears when a table view gives you a plain UITableViewCell, but your code force-casts it to a custom subclass. The cause is almost never the cast itself. The real problem is that the cell registration, storyboard settings, or reuse identifier does not match the type you expect.

Why the Cast Fails

UITableView creates cells based on a reuse identifier. When you ask for a cell, the table view returns whichever class is registered for that identifier. If the identifier is connected to a base UITableViewCell in Interface Builder, or if you registered the wrong class in code, Swift cannot turn that object into your custom subclass.

A crash usually comes from code like this:

swift
let cell = tableView.dequeueReusableCell(withIdentifier: "ProfileCell", for: indexPath) as! ProfileCell

The force cast with as! assumes the configuration is correct. If the actual runtime type is UITableViewCell, the app terminates immediately.

Correct Setup in Storyboard or Nib

The custom class, module, and reuse identifier must all agree. If you use a storyboard prototype cell, open the cell in Interface Builder and verify these fields:

  • 'Class is set to your subclass, such as ProfileCell'
  • 'Module points to the current app target'
  • 'Reuse Identifier matches the string used in dequeueReusableCell'

Then define the subclass normally:

swift
1import UIKit
2
3final class ProfileCell: UITableViewCell {
4    @IBOutlet weak var nameLabel: UILabel!
5    @IBOutlet weak var roleLabel: UILabel!
6
7    func configure(name: String, role: String) {
8        nameLabel.text = name
9        roleLabel.text = role
10    }
11}

Use safe dequeuing in your data source:

swift
1import UIKit
2
3final class PeopleViewController: UIViewController, UITableViewDataSource {
4    @IBOutlet private weak var tableView: UITableView!
5
6    private let people = [
7        ("Ava", "Designer"),
8        ("Leo", "Engineer"),
9        ("Mina", "Product Manager")
10    ]
11
12    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
13        people.count
14    }
15
16    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
17        guard let cell = tableView.dequeueReusableCell(
18            withIdentifier: "ProfileCell",
19            for: indexPath
20        ) as? ProfileCell else {
21            fatalError("Expected ProfileCell for reuse identifier ProfileCell")
22        }
23
24        let person = people[indexPath.row]
25        cell.configure(name: person.0, role: person.1)
26        return cell
27    }
28}

The guarded cast still stops execution if configuration is wrong, but it gives you a clearer failure point while avoiding a cryptic cast crash.

Registration Issues in Code

If you are not using storyboard prototype cells, you must register the correct class or nib before the table view dequeues anything. This is a common source of mistakes, especially when a project mixes nib-based and storyboard-based cells.

swift
1override func viewDidLoad() {
2    super.viewDidLoad()
3
4    let nib = UINib(nibName: "ProfileCell", bundle: nil)
5    tableView.register(nib, forCellReuseIdentifier: "ProfileCell")
6}

Two configurations frequently break things:

  • Registering UITableViewCell.self for "ProfileCell" while expecting ProfileCell
  • Using "ProfileCell" in code but "profileCell" in the storyboard

The reuse identifier is just a string, so Swift cannot detect those mismatches at compile time.

Common Pitfalls

  • Setting the reuse identifier correctly but forgetting to change the cell class in Interface Builder.
  • Leaving the module blank or incorrect when the cell class lives in the app target.
  • Registering a class in code that overrides a storyboard configuration you thought was active.
  • Reusing the same identifier for two different cell subclasses in different scenes.
  • Connecting outlets to a custom cell class, then accidentally returning a plain UITableViewCell.

Summary

  • The crash means the runtime cell type does not match the subclass your code expects.
  • Check the cell class, module, and reuse identifier together because all three must align.
  • If you use nibs or class registration, verify the registered type matches the expected subclass.
  • Prefer as? with guard while debugging so failures point to the exact dequeue site.
  • Avoid reuse identifier typos by defining them once and reusing the same string consistently.

Course illustration
Course illustration

All Rights Reserved.