daspianist
daspianist

Reputation: 5495

Programmatically adding constraints to cell: cannot find its contentView

I am trying to add constraints to subviews in my UITableViewCell, but am getting the error Unable to interpret '|' character, because the related view doesn't have a superview

Here is my custom UITableViewCell class:

class MessageTableViewCell: UITableViewCell {

var titleLabel: UILabel {
    get {
        let titleLabel = UILabel()
        titleLabel.translatesAutoresizingMaskIntoConstraints = false
        titleLabel.font = UIFont.boldSystemFont(ofSize: self.defaultFontSize)

        return titleLabel
    }
}

var bodyLabel: UILabel {
    get {
        let bodyLabel = UILabel()
        bodyLabel.translatesAutoresizingMaskIntoConstraints = false
        bodyLabel.font = UIFont.systemFont(ofSize: self.defaultFontSize)

        return bodyLabel
    }
}
var thumbnailView: UIImageView {
    get {
        let thumbnailView = UIImageView()
        thumbnailView.translatesAutoresizingMaskIntoConstraints = false
        thumbnailView.layer.cornerRadius = CGFloat(TableViewCellArrangements.kMessageTableViewCellAvatarHeight/2.0)
        thumbnailView.layer.masksToBounds = true

        return thumbnailView
    }
}
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {

    super.init(style: style, reuseIdentifier: reuseIdentifier)
    configureSubviews()
}

private func configureSubviews() {

    self.contentView.addSubview(thumbnailView)
    self.contentView.addSubview(titleLabel)
    self.contentView.addSubview(bodyLabel)

    let views: [String : Any] = ["thumbnailView" : thumbnailView,
                                 "titleLabel" : titleLabel,
                                 "bodyLabel" : bodyLabel]
    let metrics: [String : Any] = ["thumbSize" : TableViewCellArrangements.kMessageTableViewCellAvatarHeight,
                                   "padding" : 15,
                                   "right" : 10,
                                   "left" : 5]
    //The next line throws an exception. In fact, all the `let constraint` code will throw exceptions 
    let constraint1 = NSLayoutConstraint.constraints(withVisualFormat: "H:|-left-[thumbnailView(thumbSize)]-right-[titleLabel(>=0)]-right-|", options: .alignAllLeft, metrics: metrics, views: views)
    contentView.addConstraints(constraint1)
    let constraint2 = NSLayoutConstraint.constraints(withVisualFormat: "H:|-left-[thumbnailView(thumbSize)]-right-[bodyLabel(>=0)]-right-|", options: .alignAllLeft, metrics: metrics, views: views)
    contentView.addConstraints(constraint2)
    let constraint3 = NSLayoutConstraint.constraints(withVisualFormat: "V:|-right-[thumbnailView(thumbSize)]-(>=0)-|", options: .alignAllLeft, metrics: metrics, views: views)
    contentView.addConstraints(constraint3)

    if self.reuseIdentifier == TableViewCellArrangements.MessengerCellIdentifier {
        let constraint4 = NSLayoutConstraint.constraints(withVisualFormat: "V:|-right-[titleLabel(20)]-left-[bodyLabel(>=0@999)]-left-|", options: .alignAllLeft, metrics: metrics, views: views)
        contentView.addConstraints(constraint4)
    } else {
        let constraint5 = NSLayoutConstraint.constraints(withVisualFormat: "V:|[titleLabel]|", options: .alignAllLeft, metrics: metrics, views: views)
        contentView.addConstraints(constraint5)
    }
}

As noted above, the constraint line is where the exception is thrown. However, I have added the subviews to the contentView prior to setting the constraints, and so am confused why it thinks there is superview.

Thanks!

Upvotes: 1

Views: 237

Answers (1)

DonMag
DonMag

Reputation: 77476

You are re-creating a new instance of the elements each time they are referenced. Try it like this:

var xtitleLabel: UILabel?

var titleLabel: UILabel {
    get {
        if xtitleLabel == nil {
            xtitleLabel = UILabel()
        }
        xtitleLabel?.translatesAutoresizingMaskIntoConstraints = false
        xtitleLabel?.font = UIFont.boldSystemFont(ofSize: self.defaultFontSize)

        return xtitleLabel!
    }
}

You still refer to titleLabel throughout your code - this just results in a "create once" process.

Upvotes: 1

Related Questions