Add associated values to NSAttributedString.Key cases

Add associated values to NSAttributedString.Key cases

Hey everyone, I was working with NSAttributedString recently and noticed the following bothering me, would like to have your thought on it.

Currently, in order to use NSAttributedString APIs, we usually have codes like this one:

let attributes:[NSAttributedString.Key:Any] = [
    .font : UIFont.systemFont(ofSize: 100),
	.backgroundColor : UIColor.yellow,
	.strokeWidth : -2,
    .strokeColor : UIColor.black,
    .foregroundColor : UIColor.red,
]
let attrString = NSAttributedString(string: "A string", attributes: attributes)

We are using Any which is not cool since we know the expected value for each possible NSAttributedString.Key.

With enum and associated values in Swift, wouldn't make more sense to write the previous code like below?

let attributes:[StringAttribute] = [
    .font(.systemFont(ofSize: 100)),
    .backgroundColor(.yellow),
    .strokeWidth(-2),
    .strokeColor(.black),
    .foregroundColor(.white)
]
let attrString = NSAttributedString(string: "A string", attributes: attributes)

Advantages

Type Safety

The associated value will always have the expected value by that attribute.

Type Inference

We can leverage type inference to make the code smaller when using a static/class var/func.

Testability

Apps that strongly rely on attributed strings to set its theme

Disadvantages

Swift bridging overhead

The implementation can add some overhead to bridge the enum with this associated value

Here's a sample project I implemented a little wrapper to demonstrate this idea.

3 Likes

NSAttributedString did not drop the NS prefix to signify the Swift API bindings are not great and to leave room for a more idiomatic AttributedString down the road.

Improvements to this type will require coordination/management from the Apple Foundation framework team. I think it is just one of those things that hasn’t bubbled up the priority queue yet.

4 Likes

What a great idea, thanks.

1 Like

I've always had a pet peeve around using this dictionary too. It became much nicer once NSAttributedString.Key was introduced.

One potential issue with your proposal that the dictionary solves (by throwing an error at runtime, and through general programmer knowledge of how dictionaries work), is what happens if you duplicate a key in the array?

1 Like

Hey @jjatie, I think one possible solution would be to change the NSAttributedString custom init to receive a Set<StringAttibute> instead of an Array<StringAttribute>. Updated the demo project with this, check it out.

What do you think?

3 Likes