Easier NSLayoutConstraint interactions #2

:  ~ 1 min read

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.