:  ~ 3 min read

Easier NSLayoutConstraint interactions #2

In a previous post I talked about a new struct (LayoutPriority) and a couple of extension methods on NSLayoutConstraint to ease interacting with them. But, as I later discovered, there is no need for the new struct – we can do the same thing on UILayoutPriority itself. Let's quickly see how.

First, we move all the properties along with the operators to the extension:

extension UILayoutPriority {

   static let minNonZero = UILayoutPriority(rawValue: 1)
   static let belowDefaultLow = UILayoutPriority(rawValue: UILayoutPriority.defaultLow.rawValue - 1)
   static let defaultLow = UILayoutPriority(rawValue: UILayoutPriority.defaultLow.rawValue)
   static let aboveDefaultLow = UILayoutPriority(rawValue: UILayoutPriority.defaultLow.rawValue + 1)
   static let belowDefaultHigh = UILayoutPriority(rawValue: UILayoutPriority.defaultHigh.rawValue - 1)
   static let defaultHigh = UILayoutPriority(rawValue: UILayoutPriority.defaultHigh.rawValue)
   static let aboveDefaultHigh = UILayoutPriority(rawValue: UILayoutPriority.defaultHigh.rawValue + 1)
   static let maxNonRequired = UILayoutPriority(rawValue: UILayoutPriority.required.rawValue - 1)

}

extension UILayoutPriority {

   static func -(lhs: UILayoutPriority, rhs: Float) -> UILayoutPriority {
      return UILayoutPriority(rawValue: lhs.rawValue - rhs)
   }

   static func +(lhs: UILayoutPriority, rhs: Float) -> UILayoutPriority {
      return UILayoutPriority(rawValue: lhs.rawValue + rhs)
   }

   static func -=(lhs: inout UILayoutPriority, rhs: Float) {
      lhs = UILayoutPriority(rawValue: lhs.rawValue - rhs)
   }

}

Finally, we just have to update the methods in NSLayoutConstraint's extension:

extension NSLayoutConstraint {

   func with(priority: UILayoutPriority) -> NSLayoutConstraint {
      self.priority = priority
      return self
   }

}

Now we have the same functionality as before, without the need of an extra type; and we get to keep the same short syntax, chaining and operators:

someView.leadingAnchor
  .constraint(equalTo: otherView.leadingAnchor)
  .with(priority: .defaultHigh - 1)
  .activate()

The other advantage to this approach is that setContentCompressionResistancePriority:for: and setContentHuggingPriority:for: are using UILayoutPriority, so we can now pass our new constants, instead of creating new methods for those, or bridging LayoutPriority to UIKit:

// Built-in
let priority = UILayoutPriority(rawValue: UILayoutPriority.defaultLow.rawValue - 1)
view.setContentCompressionResistancePriority(priority, for: .vertical)

// Previous
view.setContentCompressionResistancePriority(LayoutPriority.belowDefaultLow.toUIKit, for: .vertical)

// New
view.setContentCompressionResistancePriority(.belowDefaultLow, for: .vertical)

In hindsight, I have no idea why I went that route, instead of this one.