Incredibly small+compact+clever Swift code for descriptive Auto Layout constraints.

I book marked SwiftAutoLayout when I first saw it announced. This amazingly compact and innovative bit of code was written by a young Canadian student Indragie Karunaratne.

Currently, there are several popular DSLs for doing Auto Layout related work (mostly creating constraints), but they are all (IMHO) way to large and all encompassing. Indragie’s code is lightweight, clear, and does most of what you’d want. I often evaluate code I use with the question: “Can I maintain this if the original author abandons it?” Clearly this code falls into the “yes” category (for me and for most others too!)

This code hadn’t been updated since early this year, so I
forked it and addressed one feature request and added support for new constraint options available in iOS8.

Lets look at an example of creating two constraints:


let constraints: [NSLayoutConstraint] = [
contentView.al_centerX == rLabel.al_centerX,
detailLabel.al_baseline == rLabel.al_baseline
] // wrapped for easier viewing
contentView.addConstraints(constraints)

In this simple example, there are two equalities. More complex constraints might have a multiplier, constant, and priority, in which case they’d look like:


let constraint = view1.al_left == view2.al_right * 2 + 10 ~ 100

instead of the standard method:


let constraint = NSLayoutConstraint(item: view1,
attribute: NSLayoutAttribute.Left,
relatedBy: NSLayoutRelation.Equal,
toItem: view2,
attribute: NSLayoutAttribute.Right,
multiplier: 2.0,
constant: 10.0) // wrapped for easier viewing

constraint.priority = 100

Almost better is the wow factor you get when reading the code to understand how it works! By using extensions to UIView (the al_… attributes), these expressions get turned into ALLayoutItem structures, which you the user never see. They simply act as placeholders for values, so the expression can evaluate to a single NSLayoutConstraint!

It took me a few reads of the code to “get” it, then “Wow!”. In the end, you get an incredibly useful utility barely consuming 250 lines of code, and have the opportunity to see Swift used in a way you probably never even thought of.

[Lastly, I should add that Indragie contacted me, and has asked for a pull request so he can wrap this Swift 2.0 code into his original repository – something I will do shortly when iOS 9 goes GA.]

Amazing technique to embed non-optional assignments within a comma separated “if let” statement

The problem is, you have this complex set of assignments to complete before you can take an action, and most of them are optionals – but not all:


for cell in tableView.visibleCells {
  if let indexPath = tableView.indexPathForCell(cell) {
    let user = users[indexPath.row]
    if let ratingLabel = cell.contentView.viewWithTag(100) as? UILabel { 
      setRatingLabel(ratingLabel, user: user)
    }
  }
}

Now imagine more assignments, a few optionals then a non-optional – it regresses to the old “cascading if let” situation in pre-Swift 1.2 code.

This type of situation appears in my code all the time, so I

posted a question on the Apple internal Swift forum asking for suggestions.

Fortunately, it was answered by OOper! It seems that you can embed a non-optional assignment by prefix it with “case”:


for cell in tableView.visibleCells {
if let indexPath = tableView.indexPathForCell(cell),
   case let user = users[indexPath.row],
   let ratingLabel = cell.contentView.viewWithTag(100) as? UILabel
   {
     setRatingLabel(ratingLabel, user: user)
   }
}

I’d love to say I completely understand why it works – I think it’s because ‘case’ statements can fail or succeed. In any case all my code using this works just fine.

While looking a bit odd, the final code is more compact and easier to follow.