You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SwiftUI自定义大体积字体加载缓慢问题及优化方案咨询

SwiftUI 大体积自定义字体加载性能优化方案

针对你遇到的23.7M NotoColorEmoji字体导致启动页面耗时3秒的问题,可通过以下几种方案优化:

1. 异步预加载字体

在App启动阶段就异步加载并注册字体,避免UI渲染时才触发加载阻塞主线程。

示例代码:

import SwiftUI
import CoreText

@main
struct SwiftUICustomFontTestApp: App {
    init() {
        // 后台线程异步预加载字体
        DispatchQueue.global(qos: .background).async {
            guard let fontURL = Bundle.main.url(forResource: "NotoColorEmoji", withExtension: "ttf"),
                  let fontData = try? Data(contentsOf: fontURL),
                  let provider = CGDataProvider(data: fontData as CFData),
                  let cgFont = CGFont(provider) else {
                return
            }
            var error: Unmanaged<CFError>?
            CTFontManagerRegisterGraphicsFont(cgFont, &error)
        }
    }
    
    var body: some Scene {
        WindowGroup {
            ContentView()
        }
    }
}

2. 延迟加载字体,避免阻塞页面渲染

页面初始化时先用系统字体占位,等字体加载完成后再切换,保证启动页快速显示。

示例代码:

struct ContentView: View {
    @State private var useCustomFont = false
    
    var body: some View {
        Text("😀😃😄😁😆😅😂🤣🥲")
            .font(useCustomFont ? .custom("NotoColorEmoji", size: 18) : .system(size: 18))
            .onAppear {
                // 后台检查字体是否可用,可用后切换
                DispatchQueue.global().async {
                    if UIFont(name: "NotoColorEmoji", size: 18) != nil {
                        DispatchQueue.main.async {
                            useCustomFont = true
                        }
                    }
                }
            }
    }
}

3. 字体子集化,缩小字体体积

只保留App中实际用到的表情字符,生成体积更小的子集字体,从根源减少加载耗时。

可使用glyphhanger工具生成子集字体,命令示例:

# 提取指定表情字符,生成子集字体
glyphhanger --formats=ttf --subset=NotoColorEmoji.ttf --text="😀😃😄😁😆😅😂🤣🥲" --output=SubsetNotoColorEmoji.ttf

替换原字体为生成的子集字体即可大幅降低加载成本。

4. 单例管理字体加载状态,避免重复加载

用单例类封装字体加载逻辑,确保字体仅被加载注册一次,避免多处触发重复加载。

示例代码:

import CoreText

class FontManager {
    static let shared = FontManager()
    private var isNotoEmojiLoaded = false
    
    private init() {}
    
    func loadNotoColorEmoji() {
        guard !isNotoEmojiLoaded else { return }
        
        guard let fontURL = Bundle.main.url(forResource: "NotoColorEmoji", withExtension: "ttf"),
              let fontData = try? Data(contentsOf: fontURL),
              let provider = CGDataProvider(data: fontData as CFData),
              let cgFont = CGFont(provider) else {
            return
        }
        
        var error: Unmanaged<CFError>?
        CTFontManagerRegisterGraphicsFont(cgFont, &error)
        isNotoEmojiLoaded = true
    }
}

在App初始化时调用FontManager.shared.loadNotoColorEmoji()即可。

内容的提问来源于stack exchange,提问作者whale

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.22 20:22:44