RommelTJ RommelTJ - 8 months ago 67
Swift Question

Unable to load custom font during XCTest in framework I'm creating

I am creating a new private Framework containing common code among our apps for use with Cocoapods. I want to add the fonts we use for our apps in it. I add the fonts the regular way (created a Resources folder, dropped and copied the fonts, added the entries in the Info.plist, added the Fonts to the Font Book) and I can see and use them in the storyboard:

enter image description here

My Fonts class looks like this:

import UIKit

class USDFont: UIFont {

let name = "Texta-"

//Font weights.
enum USDFontWeight: Int {
case Thin
case Light
case Book
case Regular
case Medium
case Bold
case Heavy
case Black

//Font scales. Goes from -2 to 9.
var USDFontScaleFactor: [String: CGFloat] =
["UIContentSizeCategoryExtraSmall": -2,
"UIContentSizeCategorySmall": -1,
"UIContentSizeCategoryMedium": 0,
"UIContentSizeCategoryLarge": 1,
"UIContentSizeCategoryExtraLarge": 2,
"UIContentSizeCategoryExtraExtraLarge": 3,
"UIContentSizeCategoryExtraExtraExtraLarge": 4,
"UIContentSizeCategoryAccessibilityMedium": 5,
"UIContentSizeCategoryAccessibilityLarge": 6,
"UIContentSizeCategoryAccessibilityExtraLarge": 7,
"UIContentSizeCategoryAccessibilityExtraExtraLarge": 8,
"UIContentSizeCategoryAccessibilityExtraExtraExtraLarge": 9]

func iconFontWithSize(fontSize: CGFloat, dynamic: Bool) -> UIFont? {
let pointSize = fontSizeWithBaseFontSize(fontSize, dynamic: dynamic)
return UIFont(name: "Insight-Icons", size: pointSize)

func fontWithFontSize(fontSize: CGFloat, weight fontWeight: USDFontWeight, italic: Bool) -> UIFont {
var fontName: String = ""
if italic {
fontName = "\(name)\(fontWeight)It"
} else {
fontName = "\(name)\(fontWeight)"

return UIFont(name: fontName, size: fontSize)!

func fontWithBaseFontSize(baseFontSize: CGFloat, weight fontWeight: USDFontWeight, italic: Bool, dynamic: Bool) -> UIFont {
let fontSize = fontSizeWithBaseFontSize(baseFontSize, dynamic: dynamic)
return fontWithFontSize(fontSize, weight: fontWeight, italic: italic)

func fontSizeWithBaseFontSize(baseFontSize: CGFloat, dynamic: Bool) -> CGFloat {
if dynamic {
if let fontSizeFactor = USDFontScaleFactor[UIApplication.sharedApplication().preferredContentSizeCategory] {
return baseFontSize + (fontSizeFactor * 0.8)
return baseFontSize

However, in my Unit Test for this framework, I have the following test:

func testUSDFont() {
let myFont = USDFont()

//Check which fonts available
for family: String in UIFont.familyNames()
for names: String in UIFont.fontNamesForFamilyName(family)
print("== \(names)")

let insightIcons = myFont.iconFontWithSize(20.0, dynamic: true)
print("------ INSIGHT ICONS: \(insightIcons) ------")
XCTAssert(true, "True")

During the XCTest, neither my Insight-Icons font nor my Texta fonts are available. When I try to load them, I get nil. When I try to print them using UIFont.familyNames() I don't see my custom fonts. What am I missing?


I was able to solve this issue by loading the font file as data and then creating a font using CGFontCreateWithDataProvider. Here is my loadCustomFont method:

func loadCustomFont(name: String, fontExtension: String) -> Bool {
    let fileManager = NSFileManager.defaultManager()
    let bundleURL = NSBundle(forClass: USDFont.self).bundleURL
    do {
        let contents = try fileManager.contentsOfDirectoryAtURL(bundleURL, includingPropertiesForKeys: [], options: .SkipsHiddenFiles)
        for url in contents {
            if url.pathExtension == fontExtension {
                let fontData = NSData(contentsOfURL: url)
                let provider = CGDataProviderCreateWithCFData(fontData)
                if let font = CGFontCreateWithDataProvider(provider) {
                    CTFontManagerRegisterGraphicsFont(font, nil)
    } catch {
        print("error: \(error)")
    return true

Once I loaded fonts this way (instead of the usual Info.plist way), I was able to load the font during the XCTest.