Hello
After updating my/our devices to iOS 17 (or XCode 15, not entirely sure), the custom fonts in our application have started randomly not working. Usually it will happen after the app has been in the background for a while.
What happens is that:
- The fonts either don't load at all. For icon fonts, this means a lot of question marks.
- The fonts get swapped around, meaning regular text (Roboto, custom font) starts rendering using the icon font (Font Awesome). I can tell because I recognize the font from development.
I have no idea how to reproduce it. I tried simulating the memory warning on the simulator, but that doesn't trigger it. It did not happen when building for iOS 16 and I did not change any font logic since then. It still does not happen on devices running iOS 17 but on versions of the app built with XCode 14.
Some debug info:
XCode: 15.0.1 (15A507)
iOS: 17.1.1 (real device, I have not observed it on Simulator)
We load the custom fonts from a proprietary SPM package:
fileprivate static func registerFont(fontName: String, ext: String = "otf") {
guard let fontURL = Bundle.module.url(forResource: fontName, withExtension: ext),
let fontDataProvider = CGDataProvider(url: fontURL as CFURL),
let font = CGFont(fontDataProvider) else {
fatalError("Couldn't create font from filename: \(fontName).\(ext)")
}
var error: Unmanaged<CFError>?
CTFontManagerRegisterGraphicsFont(font, &error)
}
public static func registerFonts() {
registerFont(fontName: "Font Awesome 6 Brands-Regular-400")
registerFont(fontName: "Font Awesome 6 Duotone-Solid-900")
registerFont(fontName: "Font Awesome 6 Pro-Light-300")
registerFont(fontName: "Font Awesome 6 Pro-Regular-400")
registerFont(fontName: "Font Awesome 6 Pro-Solid-900")
registerFont(fontName: "Font Awesome 6 Pro-Thin-100")
registerFont(fontName: "Font Awesome 6 Sharp-Light-300")
registerFont(fontName: "Font Awesome 6 Sharp-Regular-400")
registerFont(fontName: "Font Awesome 6 Sharp-Solid-900")
registerFont(fontName: "Roboto-Medium", ext: "ttf")
registerFont(fontName: "Roboto-Regular", ext: "ttf")
registerFont(fontName: "RobotoMono-Regular", ext: "ttf")
}
// Similar methods for all font types and icons:
@objc public static func getDefaultFont(size: CGFloat) -> UIFont {
return UIFont.init(name: "Roboto-Regular", size: size) ?? UIFont.systemFont(ofSize: size);
}
This code is the called in didFinishLaunching,
and it would crash the app if it failed:
FontHandler.registerFonts()
To reiterate, all the fonts work when launching the app. Restarting the app always fixes it, which, combined with the fact that they get swapped around, leads me to believe that it's some kind of font caching issue.
We use the fonts in code-only (no storyboards or xibs ever). A font would be loaded like this:
let label = UILabel()
label.font = FontHandler.getDefaultFont(size: 15)
The font files ship with the SPM package itself, which contains the FontHandler
class used above.
import PackageDescription
let package = Package(
name: "MyPackageName",
defaultLocalization: "en",
platforms: [
.iOS(.v11)
],
products: [
.library(
name: "MyPackageName",
targets: ["MyPackageName"]),
],
targets: [
.target(
name: "MyPackageName",
resources: [
.process("Fonts")
]),
.testTarget(
name: "MyPackageNameTests",
dependencies: ["MyPackageName"]),
]
)