iosswiftnslayoutconstraint

Getting Warning for UI Layout in iOS "Unable to simultaneously satisfy constraints"


I have created UITableviewCell programmatically and trying to load in table view Cell has just one imageView and UIlabel.

Although the UI looks fine , but I am seeing this warning :

Unable to simultaneously satisfy constraints. Probably at least one of the constraints in the following list is one you don't want.

 
    Try this: 
        (1) look at each constraint and try to figure out which you don't expect; 
        (2) find the code that added the unwanted constraint or constraints and fix it. 
(
    "<NSLayoutConstraint:0x60000147f200 V:|-(0)-[UIView:0x7f897ea24a00]   (active, names: '|':SampleTest.MemesTableViewCell:0x7f897ea2aaf0 )>",
    "<NSLayoutConstraint:0x60000147f2f0 UIView:0x7f897ea24a00.bottom == SampleTest.MemesTableViewCell:0x7f897ea2aaf0.bottom   (active)>",
    "<NSLayoutConstraint:0x60000147f570 V:|-(10)-[UIImageView:0x7f897ea18170]   (active, names: '|':UIView:0x7f897ea24a00 )>",
    "<NSLayoutConstraint:0x60000147f110 UIImageView:0x7f897ea18170.height == 80   (active)>",
    "<NSLayoutConstraint:0x60000147eb70 UIImageView:0x7f897ea18170.bottom == UIView:0x7f897ea24a00.bottom - 20   (active)>",
    "<NSLayoutConstraint:0x60000147f4d0 'UIView-Encapsulated-Layout-Height' SampleTest.MemesTableViewCell:0x7f897ea2aaf0.height == 44   (active)>"
)

Will attempt to recover by breaking constraint 
<NSLayoutConstraint:0x60000147f110 UIImageView:0x7f897ea18170.height == 80   (active)>

My Code:

import UIKit

class MemesTableViewCell : UITableViewCell {
    
    var contentHolderView : UIView = {
        let v = UIView()
        v.translatesAutoresizingMaskIntoConstraints = false
        return v
    }()
    
    private let nameLabel = UILabel()
    var memeImageView = UIImageView()
    
    override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
        super.init(style: style, reuseIdentifier: reuseIdentifier)
        
        setupView()
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    private func setupView() {
        contentHolderView.backgroundColor = UIColor.red

        addSubview(contentHolderView)

        
        contentHolderView.addSubview(nameLabel)
        contentHolderView.addSubview(memeImageView)
        nameLabel.translatesAutoresizingMaskIntoConstraints = false
        memeImageView.translatesAutoresizingMaskIntoConstraints = false
        memeImageView.contentMode = .scaleAspectFit
        
        
        NSLayoutConstraint.activate([
            //layout contentView
            contentHolderView.topAnchor.constraint(equalTo: self.topAnchor,constant: 0),
            contentHolderView.bottomAnchor.constraint(equalTo: bottomAnchor,constant: 0),
            contentHolderView.leadingAnchor.constraint(equalTo: leadingAnchor,constant: 0),
            contentHolderView.trailingAnchor.constraint(equalTo: trailingAnchor,constant: 0),
            
            memeImageView.topAnchor.constraint(equalTo: contentHolderView.topAnchor, constant: 10),
            memeImageView.leadingAnchor.constraint(equalTo: contentHolderView.leadingAnchor, constant: 10),
            memeImageView.widthAnchor.constraint(equalToConstant: 80),
            memeImageView.heightAnchor.constraint(equalToConstant: 80),
            nameLabel.leadingAnchor.constraint(equalTo: memeImageView.trailingAnchor, constant: 10),
            nameLabel.topAnchor.constraint(equalTo: contentHolderView.topAnchor, constant: 12)
        ])

        
        if let lastView = contentHolderView.getTheLastAddedView() {
            
            lastView.bottomAnchor.constraint(equalTo: contentHolderView.bottomAnchor, constant: -20).isActive = true
        }
        
        self.layoutIfNeeded()
    }
    

}




extension UIView {
    
    func getTheLastAddedView()->UIView?{
        if let lastView = self.subviews.last{
            return lastView
        }
        return nil
    }
    
    
}

I like to know how can this warning be fixed?


Solution

  • This is a common situation when using cells with embedded views.

    As you've seen, the UI result looks fine -- because auto-layout will attempt to recover by breaking constraint, and then it re-establishes the constraint.

    To get rid of the warnings, give the constraint that ends up defining the height a less-than-required priority.

    So, change the end of your setupView() func to this:

        if let lastView = contentHolderView.getTheLastAddedView() {
            let c = lastView.bottomAnchor.constraint(equalTo: contentHolderView.bottomAnchor, constant: -20)
            c.priority = .required - 1
            c.isActive = true
            //lastView.bottomAnchor.constraint(equalTo: contentHolderView.bottomAnchor, constant: -20).isActive = true
        }
        
        // this is not needed
        //self.layoutIfNeeded()
    

    As a side note, a cell's subviews should not be added to, or constrained to, the cell itself. You should use the cell's .contentView instead:

        contentView.addSubview(contentHolderView)
    

    and then:

        NSLayoutConstraint.activate([
            //layout contentView
            contentHolderView.topAnchor.constraint(equalTo: contentView.topAnchor,constant: 0),
            contentHolderView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor,constant: 0),
            contentHolderView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor,constant: 0),
            contentHolderView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor,constant: 0),