Attributed string with custom fonts in storyboard does not load correctly

We are using custom fonts in our project. It works well in Xcode 5. In Xcode 6, it works in plain text, attributed string in code. But those attributed strings set in storyboard all revert to Helvetica when running on simulator or device, although they look all right in storyboard.

I'm not sure if it's a bug of Xcode 6 or iOS 8 SDK, or the way to use custom fonts is changed in Xcode 6 / iOS 8?


The simplest answer that worked for is to drag the fonts into FontBook. If the fonts are in your project but not in your computer's FontBook, IB sometimes has trouble finding it. Weird, but has worked for me on several occasions.


The fix for me was to use an IBDesignable class:

import UIKit

@IBDesignable class TIFAttributedLabel: UILabel {

    @IBInspectable var fontSize: CGFloat = 13.0

    @IBInspectable var fontFamily: String = "DIN Light"

    override func awakeFromNib() {
        var attrString = NSMutableAttributedString(attributedString: self.attributedText)
        attrString.addAttribute(NSFontAttributeName, value: UIFont(name: self.fontFamily, size: self.fontSize)!, range: NSMakeRange(0, attrString.length))
        self.attributedText = attrString
    }
}

Giving you this in the Interface Builder:

Interface Builder custom font with attributed string

You can set up your attributedstring just as you normal do, but you'll have to set your fontsize and fontfamily once again in the new available properties.

As the Interface Builder is working with the custom font by default, this results in a what you see is what you get, which I prefer when building apps.

Note

The reason I'm using this instead of just the plain version is that I'm setting properties on the attributed label like the linespacing, which are not available when using the plain style.


You can add custom fonts to font book.

Step1: Click on manage fonts. It opens the font book.

enter image description here

Step2: Click on plus and add your fonts.

enter image description here

Next time when you click on font with attributed text newly added font also will show in the list. But make sure your custom font added in info.plist and bundle resources.


Thanks to this thread, I've come to this solution:

private let fontMapping = [
    "HelveticaNeue-Medium": "ITCAvantGardePro-Md",
    "HelveticaNeue": "ITCAvantGardePro-Bk",
    "HelveticaNeue-Bold": "ITCAvantGardePro-Demi",
]

func switchFontFamily(string: NSAttributedString) -> NSAttributedString {
    var result = NSMutableAttributedString(attributedString: string)
    string.enumerateAttribute(NSFontAttributeName, inRange: NSRange(location: 0, length: string.length), options: nil) { (font, range, _) in
        if let font = font as? UIFont {
            result.removeAttribute(NSFontAttributeName, range: range)
            result.addAttribute(NSFontAttributeName, value: UIFont(name: fontMapping[font.fontName]!, size: font.pointSize)!, range: range)
        }
    }
    return result
}

My solution is a bit of a work around. The real solution is for apple to fix Interface Builder.

With it you can mark all the bold and italic text in interface builder using a system font, then at runtime render your custom font. May not be optimal in all cases.

 NSMutableAttributedString* ApplyCustomFont(NSAttributedString *attributedText,
                     UIFont* boldFont,
                     UIFont* italicFont,
                     UIFont* boldItalicFont,
                     UIFont* regularFont)
{

    NSMutableAttributedString *attrib = [[NSMutableAttributedString alloc] initWithAttributedString:attributedText];
    [attrib beginEditing];
    [attrib enumerateAttribute:NSFontAttributeName inRange:NSMakeRange(0, attrib.length) options:0
                    usingBlock:^(id value, NSRange range, BOOL *stop)
    {
        if (value)
        {
            UIFont *oldFont = (UIFont *)value;
            NSLog(@"%@",oldFont.fontName);

            [attrib removeAttribute:NSFontAttributeName range:range];

            if([oldFont.fontName rangeOfString:@"BoldItalic"].location != NSNotFound && boldItalicFont != nil)
                [attrib addAttribute:NSFontAttributeName value:boldItalicFont range:range];
            else if([oldFont.fontName rangeOfString:@"Italic"].location != NSNotFound && italicFont != nil)
                [attrib addAttribute:NSFontAttributeName value:italicFont range:range];
            else if([oldFont.fontName rangeOfString:@"Bold"].location != NSNotFound && boldFont != nil)
                [attrib addAttribute:NSFontAttributeName value:boldFont range:range];
            else if(regularFont != nil)
                [attrib addAttribute:NSFontAttributeName value:regularFont range:range];
        }
    }];
    [attrib endEditing];

    return attrib;
}

Inspired by this post