Search code examples
iosswiftif-statementvaluechangelistener

If constraint changed (swift)


I'm trying to define an If statement for checking if the value of a constraint has changed.

if the constraint has changed { //do this }

But I'm not sure how to use DidChange for a constraint, or if that even is the correct method.

Currently I'm using the greater than or equal to Int. But That isn't the behavior I'm after. Is there a way to write an if statement for simply checking if the value has changed?

if self.myConstraint.constant >= 50 {
        
            let delay = 0.1 * Double(NSEC_PER_SEC)
            let time = dispatch_time(DISPATCH_TIME_NOW, Int64(delay))
            
            dispatch_after(time, dispatch_get_main_queue(), {
        
                var iPath = NSIndexPath(forRow:         self.TheTableView.numberOfRowsInSection(1)-1, inSection: self.TheTableView.numberOfSections()-1)
                self.TheTableView.scrollToRowAtIndexPath(iPath, atScrollPosition: UITableViewScrollPosition.Bottom, animated: false)
        
                println("\(countElements(fieldStatus))")
            })
        }


Solution

  • Obviously you're talking about iOS AutoLayout constraints (because you're showing the .constant property in your example). NSLayoutConstraint is a class and .constant a CGFloat property in the class declaration.

    You need to override the following method from the UITraitEnvironment subclasses (of which UIViewController is one) to detect constraint set changes, because that's the only way the constraint constants will change. iOS doesn't modify the .constant property, but your code might, and if you modify .constant, then you know you modify it at the time you modify it, so no need to check for didSet(). But iOS does swap constraints depending on platform and device orientation, and you can intercept constraint set changes by overriding the traitCollectionDidChange method:

    override func traitCollectionDidChange(previousTraitCollection: UITraitCollection?) {
        // Accessing previousTraitCollection causes a crash
    }
    

    Then you can walk through the current constraints and check the value of .constant.

    Some people have posted about willSet() and didSet() property-specific methods, but that only works for properties you define in your own class. NSLayoutConstraint is not your own class, and you can't override the behavior of the .constant property, because, according to the Swift documentation on the extension keyword

    NOTE Extensions can add new functionality to a type, but they cannot override existing functionality.

    You could subclass NSLayoutConstraint and override the constant property to intercept value changes as follows, except that doesn't buy you a solution because iOS and Interface Builder will not use or honor your subclass.

    import UIkit
    class MyConstraint : NSLayoutConstraint {
        override var constant : CGFloat {
            get {
                return super.constant
            }
            set {
                // do something extra here
                super.constant = self.constant
    
           }
        }
    }