UIFont и CTFont — это классы для работы со шрифтами в iOS: UIFont из UIKit для высокоуровневой настройки текста в UILabel и UITextView, CTFont из Core Text для низкоуровневого рендеринга с полным контролем над глифами и метриками. По данным Apple Developer Documentation, UIFont используется в 90% стандартных UI-компонентов, тогда как CTFont применяется в кастомных текстовых движках и редакторах. Оба класса представляют один шрифт, но с разным уровнем абстракции.
Главное
UIFont — это класс UIKit, представляющий шрифт для отображения текста в UI-компонентах: UILabel, UITextView, UITextField. Он предоставляет простой интерфейс для получения системных и кастомных шрифтов с указанием размера, веса и стиля. UIFont не позволяет напрямую управлять кернингом, лигатурами и OpenType-фичами — для этого используется Core Text.
CTFont — это тип Core Text (CTFontRef), предоставляющий низкоуровневый доступ к шрифтовым данным. CTFont работает напрямую с Core Graphics для рендеринга, поддерживает все возможности OpenType и TrueType, включая альтернативные глифы, лигатуры и вариативные шрифты. CTFont используется внутри UIKit для рендеринга UIFont, но также доступен напрямую для кастомной отрисовки.
UIFont и CTFont поддерживают toll-free bridging — преобразование между типами без дополнительных затрат. Кастинг UIFont as CTFont или CTFont as UIFont возможен в Swift и Objective-C. Это позволяет использовать высокоуровневый API UIKit для настройки и низкоуровневый Core Text для рендеринга без копирования данных шрифта.
Оба класса используют UIFontDescriptor (UIKit) / CTFontDescriptor (Core Text) для описания характеристик шрифта: имени, размера, веса, стиля, матрицы трансформации. Descriptor — это словарь атрибутов, который можно модифицировать и создавать новые шрифты на основе существующих. Например, добавить traitItalic к descriptor и получить курсивную версию того же шрифта.
UIFont предоставляет несколько фабричных методов для создания шрифтов. systemFont(ofSize:) возвращает системный шрифт San Francisco (iOS) или Helvetica (старые версии). boldSystemFont, italicSystemFont — варианты с начертанием. preferredFont(forTextStyle:) возвращает шрифт Dynamic Type для заданного стиля: .headline, .body, .caption1, .footnote. Эти шрифты автоматически масштабируются при изменении настроек размера текста в системе.
Для загрузки кастомных шрифтов используется UIFont(name:size:) с PostScript-именем шрифта. Шрифт должен быть предварительно добавлен в Info.plist и включён в bundle приложения. По данным Apple, рекомендуется использовать UIFont для всех стандартных UI-компонентов и переходить на CTFont только при необходимости кастомного рендеринга.
Dynamic Type — система адаптивных шрифтов, введённая в iOS 7. Пользователь выбирает предпочитаемый размер текста в Настройках — от сверхмалого до сверхбольшого. UIFont.preferredFont автоматически возвращает шрифт соответствующего размера. Для корректной работы все UILabel должны иметь adjustsFontForContentSizeCategory = true. Dynamic Type обязателен для accessibility-совместимости.
UIFontDescriptor позволяет модифицировать атрибуты шрифта без создания нового экземпляра с нуля. Методы addingAttributes(_:), withSymbolicTraits(_:), withFamily(_:) возвращают новый descriptor с изменёнными параметрами. Это удобно для получения вариантов шрифта: добавить traitBold к системному шрифту и получить полужирную версию, не зная PostScript-имени.
CTFont (CTFontRef) — это тип Core Text для низкоуровневой работы со шрифтами. Он создаётся функциями CTFontCreateWithName, CTFontCreateWithFontDescriptor, CTFontCreateCopyWithAttributes. Каждая функция возвращает шрифт с указанным интерфейсом, размером и опциональными атрибутами. CTFont используется в Core Graphics для рендеринга текста на кастомных UIView через drawRect.
CTFont предоставляет доступ к метрикам, недоступным в UIFont: CTFontGetGlyphsForCharacters возвращает массив глифов для заданных символов, CTFontGetAdvancesForGlyphs — ширину каждого глифа, CTFontGetBoundingBox — границы глифа. Это необходимо для построения кастомных текстовых layout: колонок, вращения, обтекания.
CTFontGetAscent, CTFontGetDescent, CTFontGetLeading возвращают вертикальные метрики шрифта. CTFontGetUnitsPerEm — количество units на em-square, используется для расчёта пропорций. CTFontGetGlyphCount — общее количество глифов в шрифте. Эти данные критичны для полиграфической типографики и кастомных вёрсток, где требуется точное позиционирование каждого символа.
CTFont поддерживает OpenType фичи: CTFontCopyFeatures возвращает словарь доступных функций шрифта (лигатуры, альтернативные символы, кернинг), CTFontEnableFeature активирует конкретную опцию. Вариативные шрифты (Variable Fonts) настраиваются через CTFontCopyVariation и CTFontCreateCopyWithVariation, позволяя менять weight, width и slant в непрерывном диапазоне.
Создание UIFont в Swift выполняется через один из фабричных методов или прямую инициализацию по имени. Наиболее распространённый способ — systemFont(ofSize:weight:) для системных шрифтов или preferredFont(forTextStyle:) для Dynamic Type. Для кастомных шрифтов используется UIFont(name:size:) с указанием PostScript-имени.
UIFont.systemFont(ofSize:weight:) принимает UIFont.Weight — от .ultraLight до .black. Этот метод возвращает системный шрифт San Francisco с соответствующим весом. UIFont.monospacedSystemFont, UIFont.monospacedDigitSystemFont возвращают моноширинные шрифты для кода и чисел. Все системные шрифты автоматически поддерживают 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
Каждый шрифт можно напрямую присвоить свойству font UILabel или использовать в NSAttributedString через NSFontAttributeName. Шрифты системы кэшируются iOS, поэтому повторное создание системного шрифта не несёт накладных расходов.
Для использования кастомного шрифта добавьте файл TTF или OTF в bundle проекта и укажите его в Info.plist (UIAppFonts). PostScript-имя шрифта можно узнать через UIFont.familyNames и UIFont.fontNames(forFamilyName:). После регистрации шрифт доступен через UIFont(name:size:) в любой точке приложения.
// Get all font family names
for family in UIFont.familyNames {
let names = UIFont.fontNames(forFamilyName: family)
print("\(family): \(names)")
}
// Load custom font
if let customFont = UIFont(name: "MyCustomFont-Regular", size: 18) {
label.font = customFont
}
Если имя шрифта указано неверно, UIFont(name:size:) возвращает nil. Рекомендуется заранее вывести все доступные имена шрифтов через UIFont.familyNames и UIFont.fontNames(forFamilyName:) во время отладки, чтобы убедиться, что шрифт зарегистрирован корректно.
Загрузка кастомных шрифтов возможна двумя способами: статическая регистрация через Info.plist (UIAppFonts) и динамическая регистрация через CTFontManagerRegisterGraphicsFont. Первый способ проще — шрифт доступен сразу после запуска приложения. Второй используется для шрифтов, загружаемых из сети или скачиваемых по требованию.
Динамическая регистрация полезна для on-demand ресурсов: если приложение содержит 20+ шрифтов, все их можно не включать в initial bundle, а скачать при первом использовании. CTFontManagerRegisterFontsForURLs регистрирует шрифты из указанных URL. После регистрации шрифт становится доступным через UIFont(name:size:) как обычно.
Для кастомного рендеринга через Core Text используйте CTFontCreateWithName с PostScript-именем шрифта. Разница с UIFont в том, что CTFont может быть создан с матрицей трансформации (CTFontCreateWithNameAndOptions) — для создания искажённых шрифтов: наклон, масштаб по оси X, поворот. Это недоступно в UIFont без использования аффинных трансформаций.
// Create CTFont with skew matrix
var matrix = CGAffineTransform(a: 1, b: 0, c: 0.2, d: 1, tx: 0, ty: 0)
let ctFont = CTFontCreateWithName(
"Helvetica" as CFString,
24, &matrix)
// Use toll-free bridging with UIFont
let uiFont = ctFont as UIFont
label.font = uiFont
Матрица трансформации позволяет создавать italic варианты без отдельного файла шрифта. Параметр c (skew) добавляет наклон символам. Матрица также позволяет масштабировать шрифт по горизонтали — создавая сжатые или расширенные варианты одного шрифта.
Основное различие между UIFont и CTFont — уровень абстракции. UIFont предоставляет простой API для распространённых задач: получить системный шрифт, изменить размер, применить к UILabel. CTFont даёт полный контроль над шрифтом: доступ к глифам, метрикам, OpenType-таблицам и вариативным осям. Выбор зависит от задачи.
| Характеристика | UIFont | CTFont |
|---|---|---|
| Фреймворк | UIKit | Core Text |
| Создание | systemFont / preferredFont / initWithName | CTFontCreateWithName / CTFontCreateWithDescriptor |
| Доступ к глифам | Нет | CTFontGetGlyphsForCharacters |
| OpenType фичи | Ограниченный (UIFontDescriptor) | Полный доступ |
| Вариативные шрифты | Через UIFontDescriptor | CTFontCopyVariation / CreateCopyWithVariation |
| Рендеринг | Автоматически в UI-компонентах | Core Graphics, кастомный |
Для 95% задач iOS-разработки достаточно UIFont. Core Text с CTFont оправдан при создании текстовых редакторов, PDF-генераторов, книг с типографской вёрсткой или приложений с кастомным отображением редких языков.
Работа со шрифтами в iOS требует учёта производительности. Каждый уникальный шрифт загружается в память при первом обращении и занимает ресурсы. Системные шрифты San Francisco предзагружены и не создают накладных расходов. Кастомные шрифты загружаются из файла и кэшируются системой после первой загрузки.
Рекомендуется ограничивать количество уникальных шрифтов в приложении до 3-5 семейств. Каждый шрифт занимает от 50 КБ до 2 МБ в памяти. Использование разных весов одного семейства (regular, bold, medium) эффективнее, чем загрузка нескольких разных семейств.
Система кэширует созданные экземпляры UIFont, поэтому повторные вызовы UIFont.systemFont(ofSize: 16, weight: .regular) не создают новый объект. Однако UIFont(name:size:) для кастомных шрифтов не всегда кэшируется — рекомендуется сохранять часто используемые шрифты в статические свойства или кэш NSCache, чтобы избежать повторной загрузки из файла.
При динамической регистрации шрифтов через CTFontManagerRegisterGraphicsFont процесс может быть асинхронным, если файл шрифта скачивается из сети. В этом случае UILabel или UITextView должны отображать запасной системный шрифт до завершения загрузки. После регистрации шрифт становится доступным, и экран автоматически обновляет отображение текста.
Часто задаваемые вопросы
Да, UIFont и CTFont поддерживают toll-free bridging. Преобразование выполняется простым кастингом: UIFont as CTFont или CTFont as UIFont. Никаких накладных расходов или копирования данных не происходит — оба класса указывают на один объект шрифта в памяти.
Для всех UI-компонентов используйте UIFont. Он оптимизирован для UIKit, поддерживает Dynamic Type, корректно масштабируется при изменении системных настроек. CTFont оправдан только для кастомного рендеринга через Core Graphics или при необходимости доступа к низкоуровневым метрикам шрифта.
Используйте UIFont.familyNames для списка семейств и UIFont.fontNames(forFamilyName:) для PostScript-имён. Вызовите этот код в debug-режиме и найдите нужный шрифт. PostScript-имя обычно содержит название семейства и начертание: "SFProText-Regular", "HelveticaNeue-Bold".
Да, через UIFontDescriptor можно настроить вариативные оси: weight, width, slant. Однако API UIFont для вариативных шрифтов ограничен по сравнению с CTFontCopyVariation. Для полного контроля над вариативными осями используйте Core Text и CTFontCreateCopyWithVariation.
Создайте статический словарь или NSCache с ключом из комбинации имени и размера. Для системных шрифтов iOS кэширует экземпляры автоматически, но для кастомных шрифтов, созданных через UIFont(name:size:), рекомендуется сохранять объекты в кэше приложения, чтобы избежать повторной загрузки из TTF-файла.
Итоги
Мы разработаем мобильное приложение под ключ
IT Sectr создаёт приложения для iOS и Android для стартапов и бизнеса с 2017 года. Мы проконсультируем вас и предложим наилучшее решение.
Читайте также