Search code examples
swiftxcodeswift3interface-builderibdesignable

Swift 3: Designable table view cell


I'm having some trouble with visualise my custom table view cell in the interface builder.

Does anyone know how to make a @Designable table view cell?

When I import my custom table view cell in a storyboard with a tableview, only the background color is working. When I try to set the text of the label inside my table view cell, the interface builder crashes.

My setup is called from the following methods:

- override public init(style: UITableViewCellStyle, reuseIdentifier: String?)

- required public init?(coder aDecoder: NSCoder)  

I think it's because my label isn't initialised at this moment?

Code:

import UIKit

@IBDesignable class ProgressHeaderTableViewCell: UITableViewCell {

    @IBOutlet weak var headerLabel: UILabel!

    // MARK: - View methods

    override public init(style: UITableViewCellStyle, reuseIdentifier: String?) {
        super.init(style: style, reuseIdentifier: reuseIdentifier)
        self.setupNib()
    }

    // MARK: - NSCoding
    required public init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        self.setupNib()
    }

    func setupNib(){
        self.backgroundColor = UIColor.blue

//        self.headerLabel.text = "Hello world"
    }

}

Updated code:

import UIKit

@IBDesignable class CustomTableView: UITableViewCell {

@IBOutlet weak var headerLabel: UILabel!

// MARK: - View methods
override func prepareForInterfaceBuilder() {
    self.awakeFromNib()
}

override public init(style: UITableViewCellStyle, reuseIdentifier: String?) {
    super.init(style: style, reuseIdentifier: reuseIdentifier)
    //check that there are no current subviews
    if self.subviews.count == 0 {
        self.setupNib()
    }
}


// MARK: - NSCoding
required public init?(coder aDecoder: NSCoder) {
    super.init(coder: aDecoder)

    //check that there are no current subviews
    if self.subviews.count == 0 {
        self.setupNib()
    }
}


override func awakeFromNib() {
    super.awakeFromNib()

    self.backgroundColor = UIColor.blue
    if headerLabel != nil {
        self.headerLabel.text = "Hello world"
    }
}

func setupNib(){
    let bundle = Bundle(for: CustomTableView.self)
    guard let customView = bundle.loadNibNamed("CustomTableView",owner: self, options: nil)?.first as? CustomTableView else {
        return
    }
    customView.frame = self.bounds
    self.addSubview(customView)
 }
}

Thank you!


Solution

  • I think there are a couple of possible issues you can look into here. First, whenever you create a custom view you will need to associate it with the xib file name.

    func setupNib(){
        let bundle = Bundle(for: ProgressHeaderTableViewCell.self)
        guard let customView = bundle.loadNibNamed("NAME_OF_XIB_FILE_GOES_HERE",owner: self, options: nil)?.first as? ProgressHeaderTableViewCell else {
             return 
        } 
        customView.frame = self.bounds
        self.addSubview(customView)
    }
    

    Also, whenever I work with xib files, I do any view setup within the awakeFromNib() method after checking to make sure one of the expected elements is not nil.

    override func awakeFromNib() {
        if headerLabel != nil {
            self.backgroundColor = UIColor.blue
            self.headerLabel.text = "Hello world"
        }
    }
    

    Finally, I've only been able to get IBDesignables to work when I wrap the setup functions with the a check that there are no current subviews:

    override public init(style: UITableViewCellStyle, reuseIdentifier: String?) {
        super.init(style: style, reuseIdentifier: reuseIdentifier)
        //check that there are no current subviews 
        if self.subviews.count == 0 {
            self.setupNib()
        }
    }
    
    // MARK: - NSCoding
    required public init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    
        //check that there are no current subviews 
        if self.subviews.count == 0 {
            self.setupNib()
        }
    }
    

    P.S When I was learning this, I found this blog post super helpful. You may want to read through it yourself to get a handle on IBDesignable and custom views. http://supereasyapps.com/blog/2014/12/15/create-an-ibdesignable-uiview-subclass-with-code-from-an-xib-file-in-xcode-6