2
votes

I'm trying to find and think of this problem I can't find the best solution to solve it!! And I can't understand What does it mean?!

Terminating app due to uncaught exception 'NSGenericException', reason: 'Unable to activate constraint with anchors and because they have no common ancestor. Does the constraint or its anchors reference items in different view hierarchies? That's illegal.'

Code:

private let logoImageView: UIImageView = {
    let imgView = UIImageView()
    imgView.image = UIImage(named: "LogoBlue")
    return imgView
}()

func setupLogo() {

    if #available(iOS 11.0, *) {
        view.add(subview: logoImageView) { (v, p) in [
            v.topAnchor.constraint(equalTo: p.safeAreaLayoutGuide.topAnchor, constant: 50),
            v.centerXAnchor.constraint(equalTo: p.centerXAnchor),
            v.heightAnchor.constraint(equalTo: p.widthAnchor, multiplier: 0.5),
            v.widthAnchor.constraint(equalTo: p.widthAnchor, multiplier: 0.5)
        ]}
    } else {
        view.add(subview: logoImageView) { (v, p) in [
            v.topAnchor.constraint(equalTo: p.topAnchor, constant: 50),
            v.centerXAnchor.constraint(equalTo: p.centerXAnchor),
            v.heightAnchor.constraint(equalTo: p.widthAnchor, multiplier: 0.5),
            v.widthAnchor.constraint(equalTo: p.widthAnchor, multiplier: 0.5)
        ]}
    }
}

Extension:

extension UIView {
    func add(subview: UIView, createConstraints: (_ view: UIView, _ parebt: UIView) -> [NSLayoutConstraint]) {
        subview.activate(constraints: createConstraints(subview, self))
    }

    func activate(constraints: [NSLayoutConstraint]) {
        translatesAutoresizingMaskIntoConstraints = false
        NSLayoutConstraint.activate(constraints)
    }
}
1

1 Answers

2
votes

You need to add the UIView on the hierarchy before applying constraints.

In other words, you need to <#PARENT_HERE#>.addSubview(<#CHILD_HERE#>)

You can change your extension to:

extension UIView {
    func add(subview: UIView, createConstraints: (_ view: UIView, _ parebt: UIView) -> [NSLayoutConstraint]) {
        self.addSubview(subview) // <
        subview.activate(constraints: createConstraints(subview, self))
    }

    func activate(constraints: [NSLayoutConstraint]) {
        translatesAutoresizingMaskIntoConstraints = false
        NSLayoutConstraint.activate(constraints)
    }
}

This would definitely be my solution, if you can modify your extension.


Another not so fancy solution is to manually add each subview outside the extension:

func setupLogo() {
    self.view.addSubview(logoImageView) // assuming self.view is not nil
    if #available(iOS 11.0, *) {
        view.add(subview: logoImageView) { (v, p) in [
            v.topAnchor.constraint(equalTo: p.safeAreaLayoutGuide.topAnchor, constant: 50),
            v.centerXAnchor.constraint(equalTo: p.centerXAnchor),
            v.heightAnchor.constraint(equalTo: p.widthAnchor, multiplier: 0.5),
            v.widthAnchor.constraint(equalTo: p.widthAnchor, multiplier: 0.5)
        ]}
    } else {
        view.add(subview: logoImageView) { (v, p) in [
            v.topAnchor.constraint(equalTo: p.topAnchor, constant: 50),
            v.centerXAnchor.constraint(equalTo: p.centerXAnchor),
            v.heightAnchor.constraint(equalTo: p.widthAnchor, multiplier: 0.5),
            v.widthAnchor.constraint(equalTo: p.widthAnchor, multiplier: 0.5)
        ]}
    }
}

Note: This is a secondary solution, don't use both at the same time.