AttributedStrings are a wonderful way for us to describe and add rich, styled text to our apps.

We've covered a few different approaches and solutions for composing AttributedStrings over the years.

Today we'll check out at a new library, Attributed by Nicholas Maccharoli, which stands out as a modern approach to the task. Let's take a look.

We'll start by looking at the "standard" way to use AttributedStrings in Foundation:

let font = UIFont(name: "AvenirNext", size: 18.0)!

NSAttributedString(string: "Han Solo", attributes: [
  NSForegroundColorAttributeName: UIColor.black,
  NSFontAttributeName: font
])

Not too bad, but we can do better. Let's try this same thing but with Attributed:

"Han Solo".attributed(with: Attributes { $0.foreground(color: .black).font(font) })

Neat!

"Why not just use the AttributedString API that ships with Foundation?"

This is a fair question.

Imagine building an app that had many different attributed string styles. With Attributed, we're given a strongly API, allowing us to omit a couple of types. We're also able to omit the long, verbose key names.

Finally, (and perhaps most importantly) we're using a sort of "closure composition" technique.

This involves accepting a Swift closure in an initializer, giving us the anonymous argument $0 to play with. Then, we can chain function calls on to $0 to add attributes.

All of this leads to a dramatic decrease in manual typing (even with autocomplete in Xcode, writing tons of attribute collections stops being fun, quickly).

It also allows us to work more effeciently, and accurately. We can lean on our syntactic shorthand and trust in the Swift's type system to get us to the finish line.

Inheritance

Before we go, let's talk about one of the most common hiccups we can run into when writing AttributedString-related code. Inheritance.

We've all been there. We're composing an AttributedString to go into a UILabel. We're pumped because we've got the style neatly translated from the original design into code. Then we see it. The design calls for one of the words in the label to be a different color, for emphasis.

Dun, dun dun.

No worries though, with Attributed we can solve this problem quickly:

let base = Attributes().font(UIFont(name: "AvenirNext", size: 18.0)!)

let highlighted = base.foreground(color: .red)

"Han Solo is the captain of the ".attributed(with: base)
    + "Millennium Falcon".attributed(with: highlighted)

Very cool. We're able to define a base set of attributes in Attributes(), then compose new sets that inherit all the attributes of our base set.

Then, we're leaning on Attributed's extension to String and String's support of the + operator to write some super clean code.

Pro Tip: This functionality also allows us to easily build up a re-usable set of Attributes(), keeping them in one spot, then sprinkling them throughout our code.

Learn more about Attributed at git.io/attributed.