在我正在创建的框架中的 XCTest 期间无法加载自定义字体
Unable to load custom font during XCTest in framework I'm creating
我正在创建一个新的私有框架,其中包含我们的应用程序中用于 Cocoapods 的通用代码。我想在其中添加我们用于应用程序的字体。我以常规方式添加字体(创建一个 Resources 文件夹,删除并复制字体,在 Info.plist 中添加条目,将字体添加到字体簿),我可以在情节提要中看到并使用它们:
我的字体 class 看起来像这样:
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
}
}
然而,在我对该框架的单元测试中,我有以下测试:
func testUSDFont() {
let myFont = USDFont()
//Check which fonts available
for family: String in UIFont.familyNames()
{
print("\(family)")
for names: String in UIFont.fontNamesForFamilyName(family)
{
print("== \(names)")
}
}
let insightIcons = myFont.iconFontWithSize(20.0, dynamic: true)
print("------ INSIGHT ICONS: \(insightIcons) ------")
XCTAssert(true, "True")
}
在 XCTest 期间,我的 Insight-Icons 字体和我的 Texta 字体都不可用。当我尝试加载它们时,我得到了零。当我尝试使用 UIFont.familyNames() 打印它们时,我没有看到我的自定义字体。我错过了什么?
今天我自己也 运行 遇到了这个问题。似乎无法从测试中访问自定义字体。我什至试图将它们添加到测试目标中,但没有成功。我怀疑这可能是一个错误,但我认为这也可能是 Apple 有计划的限制。我建议,如果您还没有这样做,提供系统字体的 运行time 替代品,它始终可用,以防万一您的测试不会崩溃。同样,我不知道你在测试什么,加载字体是否是你测试的重要部分,但至少你的测试不会中断,你也不会破坏你的代码。这就是我所做的:
let dashboardValueLargeFont = UIFont(name: "Interstate", size: 70.0) ?? UIFont.systemFontOfSize(70.0)
希望在我们查明这是已知限制还是错误之前它对您有所帮助。无论哪种方式,都需要在以后的版本中解决。
我能够通过加载字体文件作为数据然后使用 CGFontCreateWithDataProvider 创建字体来解决这个问题。这是我的 loadCustomFont 方法:
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
}
一旦我以这种方式加载字体(而不是通常的 Info.plist 方式),我就能够在 XCTest 期间加载字体。
对于新手:我更新了 Rommels 对 Swift 4 的回答并包装成一个助手 class:
import UIKit
class FontLoader {
@discardableResult
class func loadCustomFonts(for fontExtension: String) -> Bool {
let fileManager = FileManager.default
let bundleURL = Bundle(for: FontLoader.self).bundleURL
do {
let contents = try fileManager.contentsOfDirectory(at: bundleURL, includingPropertiesForKeys: [], options: .skipsHiddenFiles)
for url in contents {
if url.pathExtension == fontExtension {
guard let fontData = NSData(contentsOf: url) else {
continue
}
let provider = CGDataProvider(data: fontData)
let font = CGFont(provider!)
CTFontManagerRegisterGraphicsFont(font, nil)
}
}
} catch {
print("error: \(error)")
}
return true
}
}
我正在创建一个新的私有框架,其中包含我们的应用程序中用于 Cocoapods 的通用代码。我想在其中添加我们用于应用程序的字体。我以常规方式添加字体(创建一个 Resources 文件夹,删除并复制字体,在 Info.plist 中添加条目,将字体添加到字体簿),我可以在情节提要中看到并使用它们:
我的字体 class 看起来像这样:
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
}
}
然而,在我对该框架的单元测试中,我有以下测试:
func testUSDFont() {
let myFont = USDFont()
//Check which fonts available
for family: String in UIFont.familyNames()
{
print("\(family)")
for names: String in UIFont.fontNamesForFamilyName(family)
{
print("== \(names)")
}
}
let insightIcons = myFont.iconFontWithSize(20.0, dynamic: true)
print("------ INSIGHT ICONS: \(insightIcons) ------")
XCTAssert(true, "True")
}
在 XCTest 期间,我的 Insight-Icons 字体和我的 Texta 字体都不可用。当我尝试加载它们时,我得到了零。当我尝试使用 UIFont.familyNames() 打印它们时,我没有看到我的自定义字体。我错过了什么?
今天我自己也 运行 遇到了这个问题。似乎无法从测试中访问自定义字体。我什至试图将它们添加到测试目标中,但没有成功。我怀疑这可能是一个错误,但我认为这也可能是 Apple 有计划的限制。我建议,如果您还没有这样做,提供系统字体的 运行time 替代品,它始终可用,以防万一您的测试不会崩溃。同样,我不知道你在测试什么,加载字体是否是你测试的重要部分,但至少你的测试不会中断,你也不会破坏你的代码。这就是我所做的:
let dashboardValueLargeFont = UIFont(name: "Interstate", size: 70.0) ?? UIFont.systemFontOfSize(70.0)
希望在我们查明这是已知限制还是错误之前它对您有所帮助。无论哪种方式,都需要在以后的版本中解决。
我能够通过加载字体文件作为数据然后使用 CGFontCreateWithDataProvider 创建字体来解决这个问题。这是我的 loadCustomFont 方法:
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
}
一旦我以这种方式加载字体(而不是通常的 Info.plist 方式),我就能够在 XCTest 期间加载字体。
对于新手:我更新了 Rommels 对 Swift 4 的回答并包装成一个助手 class:
import UIKit
class FontLoader {
@discardableResult
class func loadCustomFonts(for fontExtension: String) -> Bool {
let fileManager = FileManager.default
let bundleURL = Bundle(for: FontLoader.self).bundleURL
do {
let contents = try fileManager.contentsOfDirectory(at: bundleURL, includingPropertiesForKeys: [], options: .skipsHiddenFiles)
for url in contents {
if url.pathExtension == fontExtension {
guard let fontData = NSData(contentsOf: url) else {
continue
}
let provider = CGDataProvider(data: fontData)
let font = CGFont(provider!)
CTFontManagerRegisterGraphicsFont(font, nil)
}
}
} catch {
print("error: \(error)")
}
return true
}
}