Nik Kov Nik Kov - 3 months ago 44x
iOS Question

Init custom UITableViewCell from nib without dequeueReusableCellWithIdentifier


I need to make an array of cells. I have few custom cell classes (inheritated from UITableViewCell) with nib files.

How to init cell without registering nib in tableview and doing dequeueReusableCellWithIdentifier?
I did it like this, but don't think, that it will work:

var labelCell = CustomCellClass.initialize()

Rob Rob

I'm inferring from the discussion in comments elsewhere that the reason you want to not allow cells to be dequeued and reused is that you're having trouble keeping track of user input captured in the cells.

The bottom line is that you really should allow the cells to be dequeued and reused and just handle that appropriately. If you're having problems with cells being reused, this can be resolved by following the model-view-controller pattern.

The key is that as values change in the cell, your cell should immediately tell the view controller so that the view controller can update the model immediately. Then, when the view controller needs to later do something with the value associated with a particular row, it doesn't retrieve it from the cell, but rather from its own model.

So, I might define a protocol for the cell to inform the table view that its text field changed:

protocol CustomCellDelegate: class {
    func cell(cell: UITableViewCell, updatedCustomTextField textField: UITextField)

And I'd then define a cell class that called that delegate:

class CustomCell: UITableViewCell {
    weak var delegate: CustomCellDelegate?

    @IBOutlet weak var customTextField: UITextField!          // hook up outlet to this property in IB

    @IBAction func didChangeValue(sender: UITextField) {      // hook up "editing changed" action for the text field to this method in IB
        delegate?.cell(self, updatedCustomTextField: sender)

Now, the view controller will:

  • register the reused identifier with the NIB in question;
  • in cellForRowAtIndexPath, populate the text field and specify itself as the delegate for that cell; and
  • handle the updatedCustomTextField method to update model if user changes anything.

Thus, something like:

class ViewController: UITableViewController, CustomCellDelegate {

    var values = ["One", "Two", "Three"]  // some initial values

    private let cellIdentifier = "CustomCell"

    override func viewDidLoad() {

        tableView.registerNib(UINib(nibName: "CustomCell", bundle: nil), forCellReuseIdentifier: cellIdentifier) // or use cell prototype with storyboard identifer specified

    // MARK: UITableViewDataSource

    override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return values.count

    override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCellWithIdentifier(cellIdentifier, forIndexPath: indexPath) as! CustomCell

        // populate cell and specify delegate

        cell.delegate = self
        cell.customTextField.text = values[indexPath.row]

        return cell

    // MARK: CustomCellDelegate

    func cell(cell: UITableViewCell, updatedCustomTextField textField: UITextField) {
        // when the cell tells us that its text field's value changed, update our own model

        if let indexPath = tableView.indexPathForCell(cell), let string = textField.text {
            values[indexPath.row] = string

Many people might be inclined to simplify this further, by hooking the IBAction for the text field directly to a view controller method. That works, and eliminates the need for this protocol, but the problem is that you need to figure out with which row this particular UIKit control is associated. The common trick is to navigate up the view hierarchy to identify the appropriate cell (e.g. often the text field will be in a content view within the cell, so you grab textField.superview.superview as! UITableViewCell), but that feels a little fragile to me.

But regardless of this little detail, hopefully this illustrates the broader pattern. Rather than trying to have cells keep track of user input, you should have the cell (the "view") update the controller of any data changes immediately, and the view controller then updates the model immediately, and you no longer need to worry about the cell reuse optimizations that iOS employs.