Ana Sayfa / Blog / Custom font loading performance: 3 pitfall

Custom font loading performance: 3 pitfall

App'e custom font ekleyince launch time 200ms arttı. Font loading optimize etmenin yolları.

Custom font iOS app’e karakter katıyor. Marka tutarlılığı, differentiated UX. Ama yanlış kullanıldığında performance cost. Dentii’ye custom font eklediğimde launch time 200ms arttı, visible jank ile.

3 ana pitfall buldum ve fix ettim. Launch time’ı restore ettim. Bu yazıda deneyimi paylaşacağım.

Pitfall 1: Too many font files

Bir font genelde birden fazla file’da: Regular, Bold, Italic, Black, Light, Medium, Black Italic, Light Italic. 8 file, her biri 500KB-2MB.

Hepsi binary’e dahil ediliyor. App size artıyor, launch sırasında font system’ine register ediliyor.

Fix: Sadece kullanılan weight’leri include et.

Projende 2 font weight kullanıyorsun (Regular, Bold). Diğerlerini binary’ye ekleme. Asset catalog’a koyma, Info.plist’te UIAppFonts’ta listeleme.

Binary size’dan 3-4MB kazandım. Launch time 80ms kısaldı.

Alternative: Variable fonts. Single file, programmatic weight. GeistVF.ttf (Geist Variable) tek bir dosyada tüm weight’leri barındırıyor.

Text("Hello")
    .font(.custom("GeistVF", size: 16))
    .fontWeight(.bold)  // Automatic variable axis adjustment

Modern font’lar variable version sunuyor. Tercih et.

Pitfall 2: Font registration bottleneck

iOS app launch’unda custom font’lar registrasyon sürecinden geçiyor. 5+ font variant için belirgin gecikme.

App startup’ında automatic register:

// Info.plist UIAppFonts array
<key>UIAppFonts</key>
<array>
    <string>GeistRegular.otf</string>
    <string>GeistBold.otf</string>
</array>

Bu automatic registration senkron. Launch time’a eklemiyor.

Alternative: Async registration.

Font’ları Info.plist’e koymayıp programmatically register ediyorsun:

func registerFonts() {
    let fontURLs = Bundle.main.urls(forResourcesWithExtension: "otf", subdirectory: nil) ?? []
    
    fontURLs.forEach { url in
        var error: Unmanaged<CFError>?
        CTFontManagerRegisterFontsForURL(url as CFURL, .process, &error)
    }
}

// App launch'unda async
Task.detached(priority: .background) {
    registerFonts()
}

Background thread’te register. Main thread hızlı.

Ama dikkat: ilk UI render’dan önce font’lar hazır olmalı. Race condition olabilir.

Safer: sadece ilk ekranın font’larını synchronous register, diğerleri async.

Pitfall 3: Font metric mismatches

Default system font (SF Pro, San Francisco) çok well-tuned metrics’e sahip. Custom font’a geçince:

  • Line height değişiyor
  • Leading (satırlar arası boşluk) farklı
  • Cap height başka yerde
  • x-height uyumsuz

Result: text UI’da hizasız görünüyor. Her SwiftUI Text component’ı farklı height’ta olabilir.

Fix: Custom UIFont extension.

extension UIFont {
    static func geist(size: CGFloat, weight: UIFont.Weight = .regular) -> UIFont {
        let fontName: String
        switch weight {
        case .bold: fontName = "GeistBold"
        case .semibold: fontName = "GeistSemiBold"
        case .medium: fontName = "GeistMedium"
        default: fontName = "GeistRegular"
        }
        
        let font = UIFont(name: fontName, size: size) ?? UIFont.systemFont(ofSize: size, weight: weight)
        
        // System font ile eşleştirme için metric override
        let metrics = UIFontMetrics.default
        return metrics.scaledFont(for: font)
    }
}

Fallback: custom font load olmamışsa system font.

CSS-like approach with text styles

SwiftUI’da custom font + Dynamic Type entegrasyonu:

extension Font {
    static func geistTitle() -> Font {
        .custom("GeistBold", size: 28, relativeTo: .title)
    }
    
    static func geistBody() -> Font {
        .custom("GeistRegular", size: 16, relativeTo: .body)
    }
    
    static func geistCaption() -> Font {
        .custom("GeistMedium", size: 12, relativeTo: .caption)
    }
}

relativeTo: parameter kullanıcı’nın text size preference’ına uyum sağlıyor. Custom font + accessibility.

Font subset generation

Büyük project’lerde custom font daha da optimize edilebilir.

Font file’ında tüm Unicode karakter’leri var (Chinese, Arabic, symbols). Kullanmayacağın karakter’leri atıyorsun, font file küçülüyor.

Tool’lar:
pyftsubset (Python fonttools)
glyphhanger (Node.js)

pyftsubset GeistRegular.otf --unicodes=U+0020-007F,U+00A0-00FF --output-file=GeistRegular-subset.otf

Basic Latin (English + European) için subset. %60-70 size reduction.

Localized app için dikkat: Turkish karakter’leri unicode range’ine dahil et.

FOUT vs FOIT

Web’den gelen problem iOS’a da uyarlanabilir:

  • FOIT (Flash of Invisible Text): Font yüklenene kadar text görünmez
  • FOUT (Flash of Unstyled Text): Text önce system font ile, sonra custom’a değişir

iOS’ta default FOUT behavior. Text görünüyor, font yüklenince değişiyor. Minor flicker.

Eğer bu flicker rahatsız edici ise:

// Async load font, UI'ı aç sonra
func loadFontThenShowUI() {
    CTFontManagerRegisterFontURLs([url], .process, true) { _, _ in
        DispatchQueue.main.async {
            self.showMainUI()  // Font hazır, şimdi UI göster
        }
    }
}

App launch’ı biraz geciktiriyor ama flicker’ı önlüyor.

Licensing implications

Custom font licensing dikkat:

  • Google Fonts: free, open source
  • Adobe Fonts: Creative Cloud subscription gerekli
  • Commercial fonts (Gotham, Proxima Nova): per-platform license
  • Custom/bespoke fonts: designer contract

App’e eklenen font’un licensing iOS app için izin veriyor mu? Check et. Some fonts web OK ama native app yok.

Benchmarking

Font loading optimization öncesi/sonrası benchmark:

  • App launch time (Instruments)
  • First frame render time
  • Text rendering perf (scroll bir liste)

Dentii’de:
– Before: 850ms launch (medium phone)
– After: 650ms launch (200ms gain)

Sonuç

Custom font performance impact gerçek ama manage edilebilir. 3 pitfall:
1. Too many font files → sadece kullanılan weight’leri include
2. Font registration overhead → async registration mümkünse
3. Font metric mismatch → UIFontMetrics ile scaled font

Variable fonts modern çözüm. Subset generation size reduction. Proper licensing check.

Custom font marka değeri katıyor. Performance cost’u dikkatli management ile minimize edilebilir.

Bu konuda bir projeniz mi var?

Kısa bir özet bırakın, 24 saat içinde size dönüş yapayım.

İletişime Geç