A first look at Swift’s new AttributedString
This year, Apple is introducing a first-class Swift type for representing attributed strings — texts that are either styled, or marked up with other attributes, such as links. That means that Swift developers no longer need to use Objective-C’s NSAttributedString
to accomplish that task, which has some really neat benefits.
Value semantics
Before we even start looking at the actual APIs and capabilities of this new AttributedString
type, one big difference between it and its Objective-C counterpart is that the Swift version is a value type. That means that it’ll be passed, copied, and mutated just like other values, through Swift’s value semantics.
For example, when using NSAttributedString
, in order to perform a simple mutation (in this case by appending a new attributed string to an existing one) we have to first make a mutable copy of the string, perform our append, and then — to avoid accidentally sharing mutable state — we have to remember to convert our mutable string back to an immutable one before returning it:
func appendLink(
to string: NSAttributedString,
label: String,
url: URL
) -> NSAttributedString {
let link = NSAttributedString(string: label, attributes: [.link: url])
let copy = NSMutableAttributedString(attributedString: string)
copy.append(link)
return NSAttributedString(attributedString: copy)
}
Now let’s take a look at what the exact same logic looks like when using the new AttributedString
type instead:
func appendLink(
to string: AttributedString,
label: String,
url: URL
) -> AttributedString {
var attributes = AttributeContainer()
attributes.link = url
let link = AttributedString(label, attributes: attributes)
var string = string
string.append(link)
return string
}
At first glance, it might seem like the new API is actually somewhat of a downgrade, given that it requires a bit more code to accomplish the same task — but a huge benefit is that Swift will now automatically ensure that our mutable state stays local, and will take care of all of the copying and mutation logic for us, giving us a much safer and less error-prone result.
SwiftUI integration
Plus, AttributedString
values can be directly passed to SwiftUI’s Text
type, which makes it much easier to render texts with mixed styling or other kinds of attributes when building UIs using SwiftUI:
struct WelcomeView: View {
var user: User
var websiteURL: URL
var body: some View {
Text(attributedString)
}
private var attributedString: AttributedString {
var string = AttributedString("""
Welcome \(user.name)! Find out more about
""")
string.append(AttributedString(" "))
return appendLink(
to: string,
label: "this app here",
url: websiteURL
)
}
}
Markdown support
But that’s not all, because this year both NSAttributedString
and the new AttributedString
type are getting built-in support for Markdown. While only a basic set of Markdown features seem to be supported at this time, it’s still a very welcome change. So, rather than having to construct our string manually (like we did above), we can now use Markdown syntax instead:
struct WelcomeView: View {
...
private var attributedString: AttributedString {
try! AttributedString(
markdown: """
Welcome **\(user.name)**! \
Find out *more* about [this app here](\(websiteURL)).
"""
)
}
}
The above kind of try!
unwrapping should only be used in contexts where we’re 100% sure that our Markdown will always be valid, since our app will crash if that’s not the case. For other types of situations, using something like the do try catch
pattern is a much better option.
Note that this new API is not a replacement for Markdown-to-HTML renders (such as Ink), but rather a convenience API for creating attributed strings using a more limited version of the full Markdown spec.
Conclusion
While this was just a very quick first look at the new AttributedString
type, I’m sure that it’s going to be really useful for many developers working on Apple’s platforms — especially those who (like me) build a large part of our UIs using SwiftUI these days.
For more information about AttributedString
, check out its official documentation.
Thanks for reading!
Take the macOS Spotlight experience to the next level: Create Jira issues, manage GitHub pull requests and control other tools with a few keystrokes. Automate every-day tasks with scripts and boost your developer productivity by downloading Raycast for free.