AutoLayoutBuilder —My Swift Package to Reduce Boilerplate Code

Leverage @resultBuilder to create a DSL for UIView constraints

Chris Nevin
Better Programming

--

We are going to solve a few problems with this DSL:

  1. Setting translatesAutoresizingMaskToConstrants to false
  2. Repeating the same anchor twice
  3. Repeating the same constant multiple times
  4. Code structure: Layout code can be all over the place, this DSL aims to solve that through the use of nesting

Typically, when using auto-layout we have many blocks of code like:

This is already starting to become hard to read and we’ve only added one view, what happens when we have 10 views?

No wonder developers hate it when they need to hunt down an auto-layout bug, there’s so much reading involved!

Most developers are lazy. With that in mind, let’s remove all of the cruft and make this more succinct:

Let’s see how we can achieve this…

First, we’ll need is a way to refer to singular and arrays of NSLayoutConstraints in the same block, we can do this with a protocol.

Second, the addSubview is utilising a @resultBuilder which allows us to collect all of the NSLayoutConstraints we want to apply.

At this point we actually have all we need to do something like this:

That’s already a massive improvement over what we had at the beginning, but let’s continue…

In order to make our constraints more readable we’re going to need to store some information about them, for the sake of this example I’m just going to reference the four edge constraints we are going to use.

That provides some anchors that we can now reference/combine in our ConstraintBuilder, lets implement the ConstraintBuilding protocol first…

There you can see our anchors being used in those 4 functions, by putting this in a protocol we can extend other types with build this allows us to chain the constraints (i.e. .leading().trailing()).

Now let’s implement this protocol in our ConstraintBuilder struct. For the sake of this article, I’m just going to simplify this and just create the equalToSuperview() function.

In the above example you can see we can combine with another constraint inside our build function, this is what allows us to chain our constraints. We can now layout our redView like so:

Since all of these values are 20 we could combine this into a single function:

Now we can do what we set out to do:

We can actually nest these calls as well:

Thanks for reading!

If you’re interested in including it in your own project, there is information about the Swift Package below, it allows you to write even more succinct code with relative constraints like so:

Swift Package

The Swift Package contains vastly more functionality than described above, things like:

  • Configuration blocks within @AutoLayoutBuilder blocks
  • Constraint chaining before calling an equalTo function
  • Various equalTo functions that allow us to link to UILayoutGuide or other views.
  • [NSLayoutConstraint] storage via the store(in:) function
  • Operators (==, <=, >=) to clean up layout code
  • Setting multipliers for NSLayoutDimensions
  • Setting UILayoutPriority during constraint creation
  • Targeted management of constraints within [NSLayoutConstraint] arrays identified using NSLayoutConstraint.Attribute (setting constant, priority)
  • …and much more!

Package: https://github.com/cjnevin/AutoLayoutBuilder

--

--