UIFont et CTFont sont des classes pour travailler avec les polices sous iOS : UIFont d'UIKit pour la configuration de texte haut niveau dans UILabel et UITextView, CTFont de Core Text pour le rendu bas niveau avec un contrôle total sur les glyphes et les métriques. Selon Apple Developer Documentation, UIFont est utilisé dans 90% des composants d'interface standard, tandis que CTFont est utilisé dans les moteurs de texte personnalisés et les éditeurs. Les deux classes représentent une même police mais à différents niveaux d'abstraction.
Points clés
UIFont est une classe UIKit représentant une police pour afficher du texte dans les composants d'interface : UILabel, UITextView, UITextField. Elle fournit une interface simple pour obtenir les polices système et personnalisées avec une taille, un poids et un style spécifiés. UIFont ne permet pas un contrôle direct sur le crénage, les ligatures et les fonctionnalités OpenType — Core Text est utilisé pour cela.
CTFont est un type Core Text (CTFontRef) fournissant un accès bas niveau aux données de police. CTFont travaille directement avec Core Graphics pour le rendu, supporte toutes les fonctionnalités OpenType et TrueType, y compris les glyphes alternatifs, les ligatures et les polices variables. CTFont est utilisé en interne par UIKit pour le rendu d'UIFont, mais est également disponible directement pour le dessin personnalisé.
UIFont et CTFont supportent le Toll-Free Bridging — conversion entre types sans coût supplémentaire. Le casting UIFont as CTFont ou CTFont as UIFont est possible en Swift et Objective-C. Cela permet d'utiliser l'API haut niveau d'UIKit pour la configuration et Core Text bas niveau pour le rendu sans copier les données de police.
Les deux classes utilisent UIFontDescriptor (UIKit) / CTFontDescriptor (Core Text) pour décrire les caractéristiques de la police : nom, taille, poids, style, matrice de transformation. Un descripteur est un dictionnaire d'attributs qui peut être modifié pour créer de nouvelles polices basées sur des polices existantes. Par exemple, ajouter traitItalic à un descripteur et obtenir une version italique de la même police.
UIFont fournit plusieurs méthodes d'usine pour créer des polices. systemFont(ofSize:) retourne la police système San Francisco (iOS) ou Helvetica (versions plus anciennes). boldSystemFont, italicSystemFont — variantes avec des styles spécifiques. preferredFont(forTextStyle:) retourne une police Dynamic Type pour le style donné : .headline, .body, .caption1, .footnote. Ces polices sont mises à l'échelle automatiquement lorsque les réglages de taille de texte changent dans le système.
Pour charger des polices personnalisées, on utilise UIFont(name:size:) avec le nom PostScript de la police. La police doit d'abord être ajoutée à Info.plist et incluse dans le bundle de l'application. Selon Apple, il est recommandé d'utiliser UIFont pour tous les composants d'interface standard et de passer à CTFont uniquement lorsque le rendu personnalisé est nécessaire.
Dynamic Type est un système de polices adaptatives introduit dans iOS 7. L'utilisateur sélectionne sa taille de texte préférée dans les Réglages — de extra-petite à extra-grande. UIFont.preferredFont retourne automatiquement une police de la taille appropriée. Pour un fonctionnement correct, tous les UILabel doivent avoir adjustsFontForContentSizeCategory = true. Dynamic Type est obligatoire pour la conformité d'accessibilité.
UIFontDescriptor permet de modifier les attributs de police sans créer une nouvelle instance à partir de zéro. Les méthodes addingAttributes(_:), withSymbolicTraits(_:), withFamily(_:) retournent un nouveau descripteur avec des paramètres modifiés. C'est pratique pour obtenir des variantes de police : ajouter traitBold à la police système et obtenir une version en gras sans connaître le nom PostScript.
CTFont (CTFontRef) est un type Core Text pour le travail bas niveau avec les polices. Il est créé par CTFontCreateWithName, CTFontCreateWithFontDescriptor, CTFontCreateCopyWithAttributes. Chaque fonction retourne une police avec l'interface, la taille et les attributs optionnels spécifiés. CTFont est utilisé dans Core Graphics pour le rendu de texte sur des UIView personnalisés via drawRect.
CTFont fournit un accès à des métriques non disponibles dans UIFont : CTFontGetGlyphsForCharacters retourne un tableau de glyphes pour des caractères donnés, CTFontGetAdvancesForGlyphs — la largeur de chaque glyphe, CTFontGetBoundingBox — les limites du glyphe. Cela est nécessaire pour construire des mises en page de texte personnalisées : colonnes, rotation, habillage.
CTFontGetAscent, CTFontGetDescent, CTFontGetLeading retournent les métriques verticales de la police. CTFontGetUnitsPerEm — nombre d'unités par em-carre, utilisé pour le calcul des proportions. CTFontGetGlyphCount — nombre total de glyphes dans la police. Ces données sont cruciales pour la typographie d'impression et les mises en page personnalisées où un positionnement précis de chaque caractère est requis.
CTFont supporte les fonctionnalités OpenType : CTFontCopyFeatures retourne un dictionnaire des fonctions disponibles de la police (ligatures, caractères alternatifs, crénage), CTFontEnableFeature active une option spécifique. Les polices variables sont configurées via CTFontCopyVariation et CTFontCreateCopyWithVariation, permettant de modifier weight, width et slant dans une plage continue.
La création de UIFont en Swift se fait via l'une des méthodes d'usine ou l'initialisation directe par nom. La façon la plus courante est systemFont(ofSize:weight:) pour les polices système ou preferredFont(forTextStyle:) pour Dynamic Type. Pour les polices personnalisées, on utilise UIFont(name:size:) avec le nom PostScript spécifié.
UIFont.systemFont(ofSize:weight:) accepte UIFont.Weight — de .ultraLight à .black. Cette méthode retourne la police système San Francisco avec le poids correspondant. UIFont.monospacedSystemFont, UIFont.monospacedDigitSystemFont retournent des polices à chasse fixe pour le code et les nombres. Toutes les polices système supportent automatiquement Dynamic Type.
let regularFont = UIFont.systemFont(ofSize: 16, weight: .regular)
let boldFont = UIFont.systemFont(ofSize: 16, weight: .bold)
let headlineFont = UIFont.preferredFont(forTextStyle: .headline)
let monoFont = UIFont.monospacedSystemFont(ofSize: 14, weight: .regular)
label.font = headlineFont
Chaque police peut être directement assignée à la propriété font d'UILabel ou utilisée dans NSAttributedString via NSFontAttributeName. Les polices système sont mises en cache par iOS, donc recréer une police système n'entraîne pas de surcharge.
Pour utiliser une police personnalisée, ajoutez le fichier TTF ou OTF au bundle du projet et spécifiez-le dans Info.plist (UIAppFonts). Le nom PostScript de la police peut être trouvé via UIFont.familyNames et UIFont.fontNames(forFamilyName:). Après l'enregistrement, la police est disponible via UIFont(name:size:) depuis n'importe où dans l'application.
// Obtenir tous les noms de familles de polices
for family in UIFont.familyNames {
let names = UIFont.fontNames(forFamilyName: family)
print("\(family): \(names)")
}
// Charger une police personnalisée
if let customFont = UIFont(name: "MyCustomFont-Regular", size: 18) {
label.font = customFont
}
Si le nom de la police est spécifié incorrectement, UIFont(name:size:) retourne nil. Il est recommandé d'afficher tous les noms de police disponibles via UIFont.familyNames et UIFont.fontNames(forFamilyName:) pendant le débogage pour s'assurer que la police est correctement enregistrée.
Le chargement de polices personnalisées est possible de deux manières : l'enregistrement statique via Info.plist (UIAppFonts) et l'enregistrement dynamique via CTFontManagerRegisterGraphicsFont. La première méthode est plus simple — la police est disponible immédiatement après le lancement de l'application. La seconde est utilisée pour les polices téléchargées depuis le réseau ou les ressources à la demande.
L'enregistrement dynamique est utile pour les ressources à la demande : si l'application contient plus de 20 polices, elles peuvent toutes être exclues du bundle initial et téléchargées lors de la première utilisation. CTFontManagerRegisterFontsForURLs enregistre les polices depuis des URL spécifiées. Après l'enregistrement, la police devient disponible via UIFont(name:size:) comme d'habitude.
Pour le rendu personnalisé via Core Text, utilisez CTFontCreateWithName avec le nom PostScript de la police. La différence avec UIFont est que CTFont peut être créé avec une matrice de transformation (CTFontCreateWithNameAndOptions) — pour créer des polices déformées : inclinaison, échelle sur l'axe X, rotation. Cela n'est pas disponible dans UIFont sans utiliser de transformations affines.
// Créer CTFont avec matrice de déformation
var matrix = CGAffineTransform(a: 1, b: 0, c: 0.2, d: 1, tx: 0, ty: 0)
let ctFont = CTFontCreateWithName(
"Helvetica" as CFString,
24, &matrix)
// Utiliser le Toll-Free Bridging avec UIFont
let uiFont = ctFont as UIFont
label.font = uiFont
La matrice de transformation permet de créer des variantes italiques sans fichier de police séparé. Le paramètre c (skew) ajoute de l'inclinaison aux caractères. La matrice permet également de mettre à l'échelle la police horizontalement — créant des variantes condensées ou élargies d'une même police.
La principale différence entre UIFont et CTFont est le niveau d'abstraction. UIFont fournit une API simple pour les tâches courantes : obtenir une police système, changer la taille, appliquer à UILabel. CTFont fournit un contrôle complet sur la police : accès aux glyphes, métriques, tables OpenType et axes variables. Le choix dépend de la tâche.
| Caractéristique | UIFont | CTFont |
|---|---|---|
| Framework | UIKit | Core Text |
| Création | systemFont / preferredFont / initWithName | CTFontCreateWithName / CTFontCreateWithDescriptor |
| Accès aux glyphes | Non | CTFontGetGlyphsForCharacters |
| Fonctionnalités OpenType | Limité (UIFontDescriptor) | Accès complet |
| Polices variables | Via UIFontDescriptor | CTFontCopyVariation / CreateCopyWithVariation |
| Rendu | Automatique dans les composants d'interface | Core Graphics, personnalisé |
Pour 95% des tâches de développement iOS, UIFont est suffisant. Core Text avec CTFont se justifie lors de la création d'éditeurs de texte, de générateurs PDF, de livres avec mise en page typographique ou d'applications avec rendu personnalisé de langues rares.
Travailler avec les polices sous iOS nécessite de prendre en compte les performances. Chaque police unique est chargée en mémoire au premier accès et consomme des ressources. Les polices système San Francisco sont préchargées et ne créent pas de surcharge. Les polices personnalisées sont chargées depuis le fichier et mises en cache par le système après le premier chargement.
Il est recommandé de limiter le nombre de polices uniques dans une application à 3-5 familles. Chaque police occupe de 50 Ko à 2 Mo en mémoire. Utiliser différents poids d'une même famille (regular, bold, medium) est plus efficace que de charger plusieurs familles différentes.
Le système met en cache les instances créées de UIFont, donc les appels répétés à UIFont.systemFont(ofSize: 16, weight: .regular) ne créent pas un nouvel objet. Cependant, UIFont(name:size:) pour les polices personnalisées n'est pas toujours mis en cache — il est recommandé de stocker les polices fréquemment utilisées dans des propriétés statiques ou NSCache pour éviter un rechargement depuis le fichier.
Lors de l'enregistrement dynamique de polices via CTFontManagerRegisterGraphicsFont, le processus peut être asynchrone si le fichier de police est téléchargé depuis le réseau. Dans ce cas, UILabel ou UITextView doivent afficher une police système de secours jusqu'à la fin du chargement. Après l'enregistrement, la police devient disponible et l'écran met automatiquement à jour l'affichage du texte.
Questions fréquentes
Oui, UIFont et CTFont supportent le Toll-Free Bridging. La conversion se fait par un simple casting : UIFont as CTFont ou CTFont as UIFont. Aucune surcharge ou copie de données ne se produit — les deux classes pointent vers le même objet police en mémoire.
Pour tous les composants d'interface, utilisez UIFont. Il est optimisé pour UIKit, supporte Dynamic Type et se met à l'échelle correctement lors des changements de réglages système. CTFont ne se justifie que pour le rendu personnalisé via Core Graphics ou lorsqu'un accès aux métriques de police bas niveau est nécessaire.
Utilisez UIFont.familyNames pour une liste des familles et UIFont.fontNames(forFamilyName:) pour les noms PostScript. Appelez ce code en mode débogage et trouvez la police souhaitée. Le nom PostScript contient généralement le nom de la famille et le style : « SFProText-Regular », « HelveticaNeue-Bold ».
Oui, via UIFontDescriptor vous pouvez configurer les axes variables : weight, width, slant. Cependant, l'API UIFont pour les polices variables est limitée par rapport à CTFontCopyVariation. Pour un contrôle complet des axes variables, utilisez Core Text et CTFontCreateCopyWithVariation.
Créez un dictionnaire statique ou un NSCache avec une clé combinant nom et taille. Pour les polices système, iOS met automatiquement les instances en cache, mais pour les polices personnalisées créées via UIFont(name:size:), il est recommandé de stocker les objets dans le cache de l'application pour éviter un rechargement depuis le fichier TTF.
Résumé
Nous développerons une application mobile clé en main
IT Sectr crée des applications iOS et Android pour les startups et les entreprises depuis 2017. Nous vous conseillerons et vous proposerons la meilleure solution.
Lisez aussi