HiraginoSans-W4/W5 availability diverges between iOS 16.5.1 and iOS 18.0.1: UIFont(name:) returns nil, XIB labels fall back to Helvetica

Background

Our app previously bundled ヒラギノ角ゴシック W4.ttc and W5.ttc via UIAppFonts. App Store review flagged them under ITMS-91198 as Apple-provided fonts. We removed the bundled .ttc files and need to verify the runtime font-resolution behavior before shipping. Case C below shows the original state (with .ttc present) for comparison.

Environment

  • Same app, same code, same XIB, physical devices only.
  • Tested OS: iOS 16.5.1 (two builds: with and without bundled .ttc) and iOS 18.0.1 (without bundled .ttc).
  • Xcode 16.x.

How to read the logs

Each log has three sections:

  1. SYSTEM HIRAGINO SANS — UIFont.fontNames(forFamilyName: "Hiragino Sans"), i.e. what the OS itself provides.
  2. RAW UIFont(name:) — UIFont(name: "HiraginoSans-W4", size: 16) etc. This is the code path our App.Font wrapper uses.
  3. XIB LABEL RESOLVED — four UILabels whose XIB fontDescription specifies HiraginoSans-W3/W4/W5/W6 respectively. resolved= is label.font.fontName at runtime.

Case A — iOS 18.0.1, physical device, bundled .ttc removed

===== ENV =====
systemVersion : 18.0.1
target        : Physical Device

===== SYSTEM HIRAGINO SANS =====
    HiraginoSans-W3
    HiraginoSans-W4
    HiraginoSans-W5
    HiraginoSans-W6
    HiraginoSans-W7
    HiraginoSans-W8

===== RAW UIFont(name:) =====
HiraginoSans-W3 OK  family=Hiragino Sans
HiraginoSans-W4 OK  family=Hiragino Sans
HiraginoSans-W5 OK  family=Hiragino Sans
HiraginoSans-W6 OK  family=Hiragino Sans

===== XIB LABEL RESOLVED =====
W3Lab xib=HiraginoSans-W3 resolved=HiraginoSans-W3 family=Hiragino Sans
W4Lab xib=HiraginoSans-W4 resolved=HiraginoSans-W4 family=Hiragino Sans
W5Lab xib=HiraginoSans-W5 resolved=HiraginoSans-W5 family=Hiragino Sans
W6Lab xib=HiraginoSans-W6 resolved=HiraginoSans-W6 family=Hiragino Sans

===== END =====

Case B — iOS 16.5.1, physical device, bundled .ttc removed

===== ENV =====
systemVersion : 16.5.1
target        : Physical Device

===== SYSTEM HIRAGINO SANS =====
    HiraginoSans-W3
    HiraginoSans-W6
    HiraginoSans-W7

===== RAW UIFont(name:) =====
HiraginoSans-W3 OK  family=Hiragino Sans
HiraginoSans-W4 nil
HiraginoSans-W5 nil
HiraginoSans-W6 OK  family=Hiragino Sans

===== XIB LABEL RESOLVED =====
W3Lab xib=HiraginoSans-W3 resolved=HiraginoSans-W3 family=Hiragino Sans
W4Lab xib=HiraginoSans-W4 resolved=Helvetica family=Helvetica
W5Lab xib=HiraginoSans-W5 resolved=Helvetica family=Helvetica
W6Lab xib=HiraginoSans-W6 resolved=HiraginoSans-W6 family=Hiragino Sans

===== END =====

Case C — iOS 16.5.1, physical device, bundled .ttc present (original state)

===== ENV =====
systemVersion : 16.5.1
target        : Physical Device

===== SYSTEM HIRAGINO SANS =====
    HiraginoSans-W3
    HiraginoSans-W4
    HiraginoSans-W5
    HiraginoSans-W6
    HiraginoSans-W7

===== RAW UIFont(name:) =====
HiraginoSans-W3 OK  family=Hiragino Sans
HiraginoSans-W4 OK  family=Hiragino Sans
HiraginoSans-W5 OK  family=Hiragino Sans
HiraginoSans-W6 OK  family=Hiragino Sans

===== XIB LABEL RESOLVED =====
W3Lab xib=HiraginoSans-W3 resolved=HiraginoSans-W3 family=Hiragino Sans
W4Lab xib=HiraginoSans-W4 resolved=HiraginoSans-W4 family=Hiragino Sans
W5Lab xib=HiraginoSans-W5 resolved=HiraginoSans-W5 family=Hiragino Sans
W6Lab xib=HiraginoSans-W6 resolved=HiraginoSans-W6 family=Hiragino Sans

===== END =====

Observations

Comparing B and C (same OS, only .ttc presence differs): removing the bundled .ttc removes HiraginoSans-W4/W5 from the system font list, makes UIFont(name:) return nil for them, and makes XIB labels naming them fall back to Helvetica — not SF, not the nearest weight in the same family.

Comparing B and A (same .ttc state, only OS differs): iOS 18.0.1 ships HiraginoSans-W3–W8 in the system, so removing the bundled .ttc has no effect there.

Question 1 — System font inventory by OS version

Is there an official, versioned list of system-provided fonts (PostScript names) per iOS release?

We need to determine which Hiragino Sans weights are available on a given OS at runtime, without hard-coding assumptions. Our observations show that iOS 16.5.1 does not provide HiraginoSans-W4/W5 in the system font set, while iOS 18.0.1 provides W3–W8. If no per-version official list exists, is UIFont.familyNames / UIFont.fontNames(forFamilyName:) the recommended runtime enumeration method? Or is there a documented recommendation to avoid relying on specific PostScript names across OS versions?

Question 2 — XIB fontDescription fallback rule

When a UILabel's XIB fontDescription specifies a font PostScript name that is not available at runtime (e.g. HiraginoSans-W4 on iOS 16.5.1 after removing the bundled .ttc), we observe UIKit falls back to Helvetica — not SF, not the nearest available weight in the same family.

Is this fallback rule documented? Is it stable across iOS versions, or should we treat the fallback target as unspecified?

If the fallback target cannot be relied upon, what is the recommended approach for XIB-based layouts that must not render with an unexpected font? Must every such label be re-assigned in code after awakeFromNib / viewDidLoad? Or is there a supported way to declare a fallback chain in Interface Builder?