Attributed Strings are a fantastic way to work with rich, styled-text. (We've covered them in Bites #143 & #144 for the curious.) We've even looked at ways to improve upon how verbose the Foundation NSAttributedString API can be.

Today we'll check out another approach using a library from Eddie Kaiger called SwiftyAttributes. It dramatically improves how we work with Attributed Strings. Let's dive in.

Let's start by looking at how things work in vanilla Foundation:

let attributes: [String: AnyObject] = [
  NSFontAttributeName: UIFont(name: "AvenirNext", size: 16.0)!,
  NSUnderlineStyleAttributeName: NSNumber(value: NSUnderlineStyle.styleSingle.rawValue),
  NSForegroundColorAttributeName: UIColor.gray
]

let someString = NSAttributedString(string: "Hello World", attributes: attributes) 

The functionality is wonderful, but even in fairly standard usage thie code can prove a bit difficult to parse at a glance.

Now, let's create the same string, but let's use SwiftyAttributes's API:

let someString = "Hello World"
  .withFont(UIFont(name: "AvenirNext", size: 16.0)!)
  .withUnderlineStyle(.styleSingle)
  .withTextColor(.gray)

Neat!

Things get even nicer when we need to concatenate two NSAttributedStrings together. We've all had to do this before and it could have involved applying attributes to specific ranges, etc. Now, we can use a much more declarative and readable syntax:

let someString = "We can easily ".withFont(.systemFont(ofSize: 16)) +
                 "underline"
                   .withFont(.systemFont(ofSize: 16))
                   .withUnderlineStyle(.styleSingle) +
                 " certain words.".withFont(.systemFont(ofSize: 16))

Under the hood, SwiftyAttributes takes a pragmatic approach by extending both Swift's String type as well as NSAttributedString with a fairly comprehensive set of delicious, sugary functions:

func withFont(_ font: UIFont)
func withParagraphStyle(_ style: NSParagraphStyle)
func withTextColor(_ color: UIColor)
func withBackgroundColor(_ color: UIColor)
func withLigatures(_ ligatures: Ligatures)
func withKern(_ kernValue: Double)
func withStrikethroughStyle(_ style: NSUnderlineStyle)
func withUnderlineStyle(_ style: NSUnderlineStyle)
func withStrokeColor(_ color: UIColor)
func withStrokeWidth(_ width: Double)
func withShadow(_ shadow: NSShadow)
func withTextEffect(_ effect: String)
func withAttachment(_ attachment: NSTextAttachment)
func withLink(_ link: URL)
func withBaselineOffset(_ offset: Double)
func withUnderlineColor(_ color: UIColor)
func withStrikethroughColor(_ color: UIColor)
func withObliqueness(_ obliquenessValue: Double)
func withExpansion(_ expansion: Double)
func withWritingDirections(_ directions: [WritingDirection])

This allows us to get creative with how we mix and match the two types:

let someAttributedString = fromSomewhereElse()

let someString = someAttributedString + "\n\nNeat!".withTextColor(.brown)

Learn more about SwiftyAttributes at git.io/swiftyattributes