photo of ben szymanski

NSAttributedString and Swift 2.0

Drawing text using NSAttributedString in Swift 2.

UPDATE / EDIT

Wow I'm dumb. If you are trying to set an NSFont into the dictionary of attributes, be sure to use NSFontAttributeName and NOT NSFontNameAttribute as the key.

This is just horrible because this issue has been bothering me for days, AND I was using the correct key in the Objective-C version. I will leave this shameful post here in the hopes that any other poor soul who has made the same mistake, will find it.

The following will work:

Swift

let titleFont:NSFont = NSFont(name: "LucidaGrande", size: 8.5)!

let fontAttributes = [NSFontAttributeName: titleFont]

var drawingString = NSAttributedString(string: self.text, attributes: fontAttributes)
drawingString.drawInRect(NSMakeRect(0, 0, 250, 20))

When the Swift announcement got dropped on the world at WWDC 2014, I was somehow not enthused. It seemed like the weird direction to take and to be honest, it seemed like a mess. Like David Owens, all I really wanted was a better Objective-C.

Alas, Swift is out in the wild now and there's probably no going back, so I have tried to embrace it as best I can by making a bunch of small and useless Playgrounds and Projects. (Side Note: I am completely sold on Playgrounds. It is easily the best thing to come out of Swift.)

So, I recently tried to take this working code:

Objective-C

NSFont *titleFont = [NSFont fontWithName:@"LucidaGrande" size:8.5];

NSDictionary *fontAttributes = @{ NSFontAttributeName: titleFont };

NSAttributedString *title = [[NSAttributedString alloc] initWithString:self.text
                                                            attributes:fontAttributes];

[title drawInRect:NSMakeRect(0, 0, 250, 20)];

... and turn it into this:

Swift

let titleFont:NSFont = NSFont(name: "LucidaGrande", size: 8.5)!

let fontAttributes = [NSFontNameAttribute: titleFont]

var drawingString = NSAttributedString(string: self.text, attributes: fontAttributes)
drawingString.drawInRect(NSMakeRect(0, 0, 250, 20))

... which didn't work at all.

There were no compile or runtime errors, which made it all the more frustrating. After wasting several days in frustration trying to figure out WHY this is happening, I finally stumbled across a mildly relevant post on the Apple Developer Forums.

This is the solution:

Swift

let titleFont:NSFont = NSFont(name: "LucidaGrande", size: 8.5)!

let fontAttributes = [String(kCTFontAttributeName): titleFont]

var drawingString = NSAttributedString(string: self.text, attributes: fontAttributes)
drawingString.drawInRect(NSMakeRect(0, 0, 250, 20))

Notice that in order to set the font attribute name key in the dictionary, you need to use the kCTFontAttributeName key, then cast it to a Swift String object instead of using NSFontAttributeName. For some reason, this appears to be broken behavior, at least in Swift 2.0.

I really, REALLY want to like Swift. I want to drive right into it and leave Objective-C far behind (even though I am still quite fond of it). But right now, a little over a year after it's introduction, it still seems like Swift is not a good choice for any commercial project, and maybe even not for hobbyist projects either.