Search code examples
iosswiftuitableviewcustom-cell

IBoutlet is nil in my custom table cell?


//custom cell in one swift file

import UIKit

class CardTableViewCell: UITableViewCell {

    @IBOutlet weak var elapsedTime: UILabel!
    @IBOutlet weak var todo: UILabel!
    @IBOutlet weak var startAndStop: UIView!
    @IBOutlet weak var progress: UIView!
    @IBOutlet weak var cardView: UIView!

}

//custom Table view controller in another swift file

import UIKit

class CardFeedTableViewController: UITableViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        tableView.register(CardTableViewCell.self, forCellReuseIdentifier: "cardCell")
        tableView.delegate = self
        tableView.dataSource = self
    }

    // MARK: - Table view data source

    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        // #warning Incomplete implementation, return the number of rows
        return 3
    }


    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell: CardTableViewCell = self.tableView.dequeueReusableCell(withIdentifier: "cardCell", for: indexPath) as! CardTableViewCell
        cell.todo.text = "study"
        return cell
    }

running the app triggers a error

storyboard

I don't know why all the properties in the my table cell is nil, when I run the app.


Solution

  • There are two variants to register, but both take a parameter called forCellReuseIdentifier, which is a string that lets you register different kinds of table view cells. For example, you might have a reuse identifier "DefaultCell", another one called "Heading cell", another one "CellWithTextField", and so on. Re-using different cells this way helps save system resources.

    If you want to use register() with a Swift class, you provide a table view cell class as its first parameter. This is useful if your cell is defined entirely in code. As an example, this uses the default UITableViewCell class:

    tableView.register(UITableViewCell.self, forCellReuseIdentifier: "DefaultCell")
    

    You can then dequeue that cell like this:

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "DefaultCell")!
        return cell
    }
    

    The other option is to use register() with an Interface Builder nib file. Nibs contain the class name to use along with their design, so this method is more common. Here's an example

    tableView.register(UINib(nibName: "yourNib", bundle: nil), forCellReuseIdentifier: "CellFromNib")
    

    But if you're using storyboards you will find it easier to create prototype cells and give them a reuse identifier directly inside Interface Builder.So no need to register programmatically.

    Remove this line form viewDidLoad

    tableView.register(CardTableViewCell.self, forCellReuseIdentifier: "cardCell).