How can I fix “Unable to activate constraint ~~ ” error?

I’m trying to make ui using snapkit and practice MVVM pattern, but when I try to add stackview I keep getting an error that says

‘Unable to activate constraint with anchors <NSLayoutYAxisAnchor:0x600001753fc0 “UIStackView:0x10380aba0.centerY”> and <NSLayoutYAxisAnchor:0x600001753a00 “UIImageView:0x103905b00.centerY”> because they have no common ancestor. Does the constraint or its anchors reference items in different view hierarchies? That’s illegal.’

When I comment out the stackview code line, everything works well, so I guess there is something wrong with the stackview.

This is Post.swift code.

struct Post {
    let userHandle: String
    let userProfileImage: String
    let location: String
    let selfieImage: String
    let rearViewImage: String
    let caption: String
    
    init(userHandle: String, userProfileImage: String, location: String, selfieImage: String, rearViewImage: String, caption: String) {
        self.userHandle = userHandle
        self.userProfileImage = userProfileImage
        self.location = location
        self.selfieImage = selfieImage
        self.rearViewImage = rearViewImage
        self.caption = caption
    }
}

This is PostView.swift code.

import UIKit
import SnapKit

class PostView: UIView {
    var userProfileImageName: String = "" {
        willSet {
            userProfileImageView.image = UIImage(named: newValue)
            print("userProfileImage: \(newValue)")
        }
    }
    
    var selfieImageName: String = "" {
        willSet {
            selfieImageView.image = UIImage(named: newValue)
            print("selfieImage: \(newValue)")
        }
    }
    
    var rearImageName: String = "" {
        willSet {
            rearViewImageView.image = UIImage(named: newValue)
            print("rearImage: \(newValue)")
        }
    }
    
    let userProfileImageView: UIImageView = {
        let imageView = UIImageView()
        imageView.clipsToBounds = true
        return imageView
    }()
    
    lazy var userHandleLabel: UILabel = {
        let label = UILabel()
        label.textAlignment = .natural
        label.textColor = .white
        label.font = .systemFont(ofSize: 13, weight: .semibold)
        label.backgroundColor = .lightGray
        return label
    }()
    
    lazy var locationLabel: UILabel = {
        let label = UILabel()
        label.font = .systemFont(ofSize: 10)
        label.textColor = .lightGray
        label.backgroundColor = .black
        return label
    }()
    
    var stackView: UIStackView {
        let stackView = UIStackView()
        stackView.axis = .vertical
        stackView.spacing = 5
        return stackView
    }
    
    let selfieImageView: UIImageView = {
        let imageView = UIImageView()
        imageView.contentMode = .scaleAspectFill
        imageView.clipsToBounds = true
        imageView.layer.cornerRadius = 10.0
        return imageView
    }()
    
    let rearViewImageView: UIImageView = {
        let imageView = UIImageView()
        imageView.contentMode = .scaleAspectFill
        imageView.clipsToBounds = true
        imageView.layer.cornerRadius = 10.0
        return imageView
    }()
    
    let captionLabel: UILabel = {
        let label = UILabel()
        label.font = .systemFont(ofSize: 15.0, weight: .semibold)
        label.textColor = .white
        return label
    }()
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        backgroundColor = .darkGray
        
        addSubview(userProfileImageView)
        addSubview(stackView)

        stackView.addArrangedSubview(userHandleLabel)
        stackView.addArrangedSubview(locationLabel)
        
        addSubview(rearViewImageView)
        addSubview(captionLabel)
        
        // constraint
        userProfileImageView.snp.makeConstraints { make in
            make.top.equalToSuperview().inset(5)
            make.leading.equalToSuperview().inset(5)
            make.width.equalTo(50)
            make.height.equalTo(userProfileImageView.snp.width)
        }
        
        stackView.snp.makeConstraints { make in
            make.centerY.equalTo(userProfileImageView.snp.centerY)
make.leading.equalTo(userProfileImageView.snp.trailing).offset(5)
        }
                
        rearViewImageView.snp.makeConstraints { make inmake.top.equalTo(userProfileImageView.snp.bottom).offset(10)
            make.leading.trailing.equalToSuperview()
            // height == width * 4/3
make.height.equalTo(rearViewImageView.snp.width).multipliedBy(4.0 / 3.0)
            // don't need this
            //make.centerX.equalToSuperview()
        }
                
        captionLabel.snp.makeConstraints { make in
            make.top.equalTo(rearViewImageView.snp.bottom).offset(5)
            make.leading.equalTo(rearViewImageView.snp.leading)
            make.trailing.equalTo(rearViewImageView.snp.trailing)
            make.bottom.equalToSuperview().inset(10)
        }
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

This is PostViewModel.swift code.

class PostViewModel {
    private let post: Post
    
    init(post: Post) {
        self.post = post
    }
    
    var userHandle: String {
        return post.userHandle
    }
    
    var userProfileImage: String {
        return post.userProfileImage
    }
    
    var location: String {
        return post.location
    }
    
    var selfieImage: String{
        return post.selfieImage
    }
    
    var rearViewImage: String {
        return post.rearViewImage
    }
    
    var caption: String {
        return post.caption
    }
}

extension PostViewModel {
    func configure(_ view: PostView){
        view.locationLabel.text = location
        view.captionLabel.text = caption
        view.rearImageName = rearViewImage
        view.selfieImageName = selfieImage
        view.userProfileImageName = userProfileImage
        
        view.userProfileImageView.layer.cornerRadius = 25
        print("== \(view.userProfileImageView.layer.cornerRadius)")
    }
}

This is the viewcontroller.

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.

        let newPost = Post(userHandle: "userHandle", userProfileImage: "profileImage.png", location: "A location", selfieImage: "selfieImage.jpg", rearViewImage: "rearImage.jpg", caption: "BeReal")
        //let postView = PostView()
        let postViewModel = PostViewModel(post: newPost)
        let postView = PostView()
        postViewModel.configure(postView)

        view.addSubview(postView)

        postView.snp.makeConstraints { make in
            //make.centerY.equalToSuperview()
            make.leading.trailing.equalToSuperview()
        }

        postView.backgroundColor = .lightGray
    }
}

I also tried making the stackview’s constraint with equalToSuperview(), but I get Fatal error: Expected superview but found nil when attempting make constraint equalToSuperview. error, so I guess stackview is not being added…?
I also double-checked that I’m adding subview before making constraints. I just can’t figure out what causes this error.

  • 1. Don’t use the same view when setting constraint to the same view, in your case “userProfileImageView” and “rearViewImageView” 2. remove this line “make.width.equalTo(userProfileImageView.snp.height).multipliedBy(1.0)” and set a height constraint for that view(userProfileImageView) 3. stackView is not having height and width constraint

    – 




Leave a Comment