swiftuitableviewuikittablecell

fatal error - UIKit tablecell will not dequeue


I am in the process of learning uikit and having trouble with tables and cells. I have a project currently with a table view, programmatic, no storyboard that is giving me a error when trying to dequeue the table cell.

Fatal Error: The table cell could not dequeue a CustomCell in ViewController

The app crashes at the cell creation in the tableView.

I have checked over the tableview and custom cell for any mismatch in spelling but it all seems to line up. I expect the table to show a few images in a dummy array of UIImages. Thanks for any help.

Custom Cell

class CustomCell: UITableViewCell {
    
    static let identifier = "CustomCell"
    
    private let myImageView: UIImageView = {
        let iv = UIImageView()
        iv.contentMode = .scaleToFill
        iv.image = UIImage(systemName: "photo")
        iv.tintColor = .label
        return iv
    }()
    
    private let myLabel: UILabel = {
        let label = UILabel()
        label.textColor = .label
        label.textAlignment = .left
        label.font = .systemFont(ofSize: 24, weight: .medium)
        label.text = "Error"
        return label
    }()
    
    override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
        super.init(style: style, reuseIdentifier: reuseIdentifier)
        self.setupUI()
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    public func configure(with image: UIImage, and label: String) {
        self.myImageView.image = image
        self.myLabel.text = label
    }
    
    private func setupUI() {
        self.contentView.addSubview(myImageView)
        self.contentView.addSubview(myLabel)
        
        myImageView.translatesAutoresizingMaskIntoConstraints = false
        myLabel.translatesAutoresizingMaskIntoConstraints = false
        
        NSLayoutConstraint.activate([
            // setup the image constraints
            myImageView.topAnchor.constraint(equalTo: self.contentView.layoutMarginsGuide.topAnchor),
            myImageView.bottomAnchor.constraint(equalTo: self.contentView.layoutMarginsGuide.bottomAnchor),
            myImageView.leadingAnchor.constraint(equalTo: self.contentView.layoutMarginsGuide.leadingAnchor),
            //            myImageView.heightAnchor.constraint(equalToConstant: 90),
            myImageView.widthAnchor.constraint(equalToConstant: 90),
            // setup the label constraints
            myLabel.leadingAnchor.constraint(equalTo: self.myImageView.trailingAnchor, constant: 16),
            myLabel.trailingAnchor.constraint(equalTo: self.contentView.trailingAnchor, constant: -12),
            myLabel.topAnchor.constraint(equalTo: self.contentView.topAnchor),
            myLabel.topAnchor.constraint(equalTo: self.contentView.topAnchor)
            
        ])
    }
}

Table viewcontroller

class ActivityVC: UIViewController {
    
    var user: User!
    let gear = UITableView()
    
    private let images: [UIImage] = [
        UIImage(named: "0")!,
        UIImage(named: "1")!,
        UIImage(named: "2")!,
    
    ]
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        self.tableView.dataSource = self
        self.tableView.delegate = self
        
        setupUI()
        setupNavControl()
        
    }
    
    private let tableView: UITableView = {
        let tableView = UITableView()
        tableView.backgroundColor = .systemBackground
        tableView.allowsSelection = false
        tableView.separatorStyle = .singleLine
        tableView.register(UITableViewCell.self, forCellReuseIdentifier: CustomCell.identifier)
        
        return tableView
    }()
     
    private func setupUI() {
        self.view.backgroundColor = .systemBackground
        
        self.view.addSubview(tableView)
        tableView.translatesAutoresizingMaskIntoConstraints = false
        
        NSLayoutConstraint.activate([
            tableView.topAnchor.constraint(equalTo: self.view.topAnchor),
            tableView.bottomAnchor.constraint(equalTo: self.view.bottomAnchor),
            tableView.leadingAnchor.constraint(equalTo: self.view.leadingAnchor),
            tableView.trailingAnchor.constraint(equalTo: self.view.trailingAnchor)
        ])
    }
     
extension ActivityVC: UITableViewDelegate, UITableViewDataSource {
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return self.images.count
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        guard let cell = tableView.dequeueReusableCell(withIdentifier: CustomCell.identifier, for: indexPath) as? CustomCell else {
            fatalError("The table cell could not dequeue a CustomCell in ViewController")
        }
        
        let image = self.images[indexPath.row]
        cell.configure(with: image, and: indexPath.row.description)
        
        return cell
    }
    
    func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        return 112.5
    }
}

Solution

  • The problem is with this line from ActivityVC:

    tableView.register(UITableViewCell.self, forCellReuseIdentifier: CustomCell.identifier)
    

    You are registering the class UITableViewCell, but you are using CustomCell. Although CustomCell comes from UITableViewCell, the casting fails.

    You can fix it by changing it to:

    tableView.register(CustomCell.self, forCellReuseIdentifier: CustomCell.identifier)