Search code examples
iosswift3nslayoutconstraint

Am I adding yet another, or changing, this constraint?


Say I do this ...

override func viewDidLoad() {
   super.viewDidLoad()
   view.heightAnchor.constraint(equalToConstant: 50).isActive = true

later, I do this ...

view.heightAnchor.constraint(equalToConstant: 51).isActive = true

am I a bad person?

Have I now redundantly added a second constraint (what happens to the first?)

Or does it know to change the first?

Or does something else happen? Am I making a leak?

What should I do, and in what way have I been bad, if any?

What's the correct thing to do here?


Solution

  • view.heightAnchor.constraint(equalToConstant: 50).isActive = true
    

    later, I do this ...

    view.heightAnchor.constraint(equalToConstant: 51).isActive = true
    

    am I a bad person?

    Yes, and if I'm not mistaken, the runtime will tell you so with a loud message in the console warning that you have unsatisfiable (conflicting) constraints. You have a constraint setting the height to 50 and another setting the height to 51 and both things cannot be true.

    You didn't give enough code to be sure of what's going on in your case, but you can easily see that what I'm saying is correct, by making your view controller's code consist only of the following:

    func delay(_ delay:Double, closure:@escaping ()->()) {
        let when = DispatchTime.now() + delay
        DispatchQueue.main.asyncAfter(deadline: when, execute: closure)
    }
    class ViewController: UIViewController {
    
        override func viewDidLoad() {
            super.viewDidLoad()
            let v = UIView()
            v.translatesAutoresizingMaskIntoConstraints = false
            self.view.addSubview(v)
            v.topAnchor.constraint(equalTo: self.view.topAnchor).isActive = true
            v.leadingAnchor.constraint(equalTo: self.view.leadingAnchor).isActive = true
            v.widthAnchor.constraint(equalToConstant: 100).isActive = true
            v.heightAnchor.constraint(equalToConstant: 50).isActive = true
            delay(3) {
                v.heightAnchor.constraint(equalToConstant: 51).isActive = true
            }
        }
    
    }
    

    As you stipulated, we "later" add the 51 constraint — and as I said, the runtime squawks at that moment.

    The correct procedure is to keep a reference to the original constraint so that you can change its constant later. (Under more complex circumstances you could actually deactivate, i.e. remove, the first constraint before adding the second, but if all you plan to do is alter the constant, that's not necessary, as it is mutable.)