Font Descriptor: ключевые понятия и возможности дескриптора шрифта

Автор: IT Sectr Опубликовано: 2026-07-23 Время чтения: 9 мин

Font Descriptor — это объект UIFontDescriptor в iOS и NSFontDescriptor в macOS, который инкапсулирует все метаданные шрифта: семейство, начертание, размер, межбуквенный интервал, межстрочный интервал и атрибуты типографики. Вместо того чтобы создавать шрифт напрямую через UIFont(name:size:), разработчик описывает желаемые характеристики через дескриптор, а система подбирает наилучшее соответствие из доступных шрифтов. По данным Apple Developer Documentation, UIFontDescriptor поддерживает более 20 атрибутов шрифта и используется во всех фреймворках типографики iOS — от UIKit до Core Text и SwiftUI.

Главное

  • Font Descriptor — объект-описатель шрифта, содержащий метаданные о семействе, начертании, размере и атрибутах типографики
  • Позволяет создавать UIFont из набора атрибутов без указания конкретного имени шрифта
  • Поддерживает модификацию существующего шрифта: изменение размера, начертания, кернинга без создания нового объекта
  • Используется в UIKit, Core Text и SwiftUI для поиска и настройки шрифтов
  • Обеспечивает шрифтовой матчинг — автоматический подбор ближайшего доступного начертания

Что такое Font Descriptor и зачем он нужен

Font Descriptor — это объект, который описывает характеристики шрифта как набор пар ключ-значение, а не как конкретный файл шрифта. Вместо создания шрифта по имени разработчик задаёт семейство, начертание, размер и опциональные атрибуты, а система подбирает наилучшее соответствие. Такой подход критичен для адаптивной типографики: один и тот же дескриптор может работать на разных версиях iOS, где набор доступных шрифтов отличается. По данным iOS Human Interface Guidelines, шрифтовой матчинг через дескрипторы — рекомендуемый способ работы с динамическими шрифтами.

Без Font Descriptor разработчику пришлось бы проверять доступность каждого шрифта по имени и вручную определять fallback-варианты. Дескриптор автоматизирует этот процесс: он содержит матрицу совместимости начертаний — нормальное, полужирное, курсивное, полужирный курсив — и при отсутствии точного совпадения возвращает ближайшее доступное. Системный матчинг работает на уровне Core Text и доступен как на iOS, так и на macOS через единый NSFontDescriptor API.

Дескрипторы также используются для пользовательских шрифтов — загруженных через Info.plist или добавленных вручную. Если шрифт зарегистрирован в системе, его дескриптор создаётся точно так же, как для системного. Cross-platform заметка: концепция дескриптора существует и в Android через Typeface.Builder, но iOS-реализация через UIFontDescriptor даёт значительно больше атрибутов — более 20 против 5 в Android.

Основные свойства и атрибуты Font Descriptor

UIFontDescriptor содержит атрибуты, сгруппированные в словарь fontAttributes типа [UIFontDescriptor.AttributeName: Any]. Ключевые атрибуты включают семейство шрифта (family), имя (name), размер (size), начертание (traits), матрицу трансформации (matrix), визуальный размер (opticalSize) и текстовый стиль (textStyle). По данным Apple WWDC 2019 Session 227, использование текстовых стилей — Dynamic Type — обязательно для accessibility-совместимых приложений.

Атрибут traits — это словарь, содержащий символьные характеристики: жирность (UIFontWeightTrait), курсивность (UIFontSlantTrait), ширина (UIFontWidthTrait) и другие. Эти значения используются шрифтовым матчером для подбора начертания. Например, UIFontWeightTrait со значением 0.0 — нормальное начертание, 0.3 — полужирное. Система автоматически маппит числовые значения в доступные варианты шрифта.

Дополнительные атрибуты включают featureSettings для OpenType-фич (лигатуры, кернинг, цифровые пропорции), visibleName для отображения пользователю, matrix для аффинных трансформаций шрифта и cascadeList для каскадных списков fallback-шрифтов. Полный список атрибутов покрывает практически все сценарии типографики в iOS и macOS.

АтрибутТипОписание
UIFontDescriptorFamilyStringСемейство шрифта (SF Pro, Helvetica Neue)
UIFontDescriptorNameStringПолное имя шрифта (HelveticaNeue-Bold)
UIFontDescriptorSizeNSNumberРазмер шрифта в пунктах
UIFontDescriptorMatrixNSValueАффинная матрица трансформации
UIFontDescriptorTraits[String: Any]Символьные характеристики начертания
UIFontDescriptorTextStyleStringСтиль Dynamic Type (headline, body, caption)

Создание UIFont через Font Descriptor на Swift

Основной способ работы с Font Descriptor в iOS — создание дескриптора с последующей генерацией UIFont. Это предпочтительный подход, когда нужно получить шрифт с определёнными характеристиками, не зная точного имени. Процесс состоит из двух шагов: создание UIFontDescriptor через инициализатор и вызов метода font(withSize:) на дескрипторе.

swift
import UIKit

// Create font descriptor for family
let descriptor = UIFontDescriptor.init(
    fontAttributes: [
        .family: "SF Pro",
        .traits: [
            .weight: UIFont.Weight.bold
        ]
    ]
)

// Generate UIFont from descriptor
let font = descriptor.font(withSize: 17)

Этот подход гарантирует, что система подберёт наилучшее соответствие для жирного начертания SF Pro на текущем устройстве. Ключевое преимущество — код не зависит от версии iOS: на iOS 13 будет использован SF Pro, на более ранних — Helvetica Neue или системный шрифт по умолчанию.

Для создания шрифта с динамическим размером используется инициализатор со стилем текста и масштабом. Dynamic Type автоматически подстраивает размер под настройки пользователя:

swift
// Dynamic Type descriptor
let bodyDescriptor = UIFontDescriptor
    .preferredFontDescriptor(withTextStyle: .body)

// Make font bold
let boldDescriptor = bodyDescriptor.withSymbolicTraits([.traitBold])

// Generate UIFont preserving dynamic size
let boldBodyFont = UIFont(
    descriptor: boldDescriptor!,
    size: bodyDescriptor.pointSize
)

Важно: метод withSymbolicTraits возвращает опциональный дескриптор — если запрошенное начертание недоступно, возвращается nil. Всегда проверяйте опционал перед использованием.

Модификация атрибутов через добавление и замену

Font Descriptor поддерживает иммутабельную модель — каждый метод модификации возвращает новый дескриптор с изменённым атрибутом. Это соответствует value-семантике и делает код предсказуемым: исходный дескриптор никогда не меняется. Основные методы модификации: addingAttributes для добавления атрибутов, withFace для изменения начертания, withSize для изменения размера, withMatrix для аффинной трансформации.

Метод addingAttributes — наиболее гибкий. Он принимает словарь атрибутов и возвращает новый дескриптор. При совпадении ключей новые значения заменяют старые. Это позволяет комбинировать изменения: добавить вес, изменить размер и включить лигатуры одним вызовом. По данным Apple Technical Q&A QA1682, addingAttributes — рекомендуемый способ массовой модификации через расширение.

Практическое применение: создание шрифта для моноширинного текста в редакторе кода. Разработчик берёт системный моноширинный дескриптор, добавляет пониженный вес для тонких линий и увеличивает межбуквенный интервал через featureSettings. Это даёт более читаемый код без загрузки отдельного шрифта.

swift
let monoDescriptor = UIFontDescriptor.monospacedDigitFontDescriptor()

// Add custom attributes
let customDescriptor = monoDescriptor.addingAttributes([
    .size: 14,
    .traits: [
        .weight: UIFont.Weight.medium
    ]
])

let monoFont = UIFont(
    descriptor: customDescriptor,
    size: 14
)

Ограничение: не все атрибуты можно изменить после создания дескриптора. Например, семейство шрифта (family) задаётся один раз при инициализации. Если нужно изменить семейство, создавайте новый дескриптор. Это связано с архитектурой Core Text, где дескриптор привязан к конкретному шрифтовому ресурсу.

Шрифтовой матчинг и поиск системных шрифтов

Шрифтовой матчинг — ключевая функция Font Descriptor, которая автоматически подбирает наилучшее соответствие запрошенным атрибутам среди установленных шрифтов. Процесс включает три этапа: фильтрация (отсев несовместимых шрифтов), ранжирование (сортировка по степени соответствия) и выбор (возврат наилучшего результата). Матчинг выполняется на уровне Core Text — фреймворка, лежащего в основе всей типографики iOS.

Для поиска всех шрифтов, соответствующих дескриптору, используется метод matchingFontDescriptors. Он возвращает массив дескрипторов, отсортированных по релевантности. Разработчик может выбрать точное совпадение (первый элемент) или перебрать варианты для кастомной логики. По данным Apple Font Handling Guide, это единственный способ получить список доступных начертаний для конкретного семейства без перечисления по имени.

Сценарий использования: при выборе шрифта в интерфейсе настройки текста. Пользователь выбирает семейство, а приложение через matchingFontDescriptors получает все доступные начертания и отображает их в picker. Без матчинга пришлось бы жёстко кодировать список вариантов, который меняется между версиями iOS.

swift
let searchDescriptor = UIFontDescriptor.init(
    fontAttributes: [.family: "SF Mono"]
)

// Get all available typefaces
let matchingDescriptors = searchDescriptor
    .matchingFontDescriptors(withMandatoryKeys: nil)

for descriptor in matchingDescriptors {
    print(descriptor.object(forKey: .visibleName) ?? "unnamed")
}

Mandatory keys — параметр, ограничивающий поиск. Если указать [.family], матчинг вернёт все шрифты указанного семейства. Если указать [.family, .traits] — только те, что совпадают и по семейству, и по начертанию. Использование mandatory keys ускоряет матчинг при поиске подмножества шрифтов.

Производительность: матчинг — синхронная операция, занимающая от 0.5 до 5 мс на iOS. Для единичного поиска это незаметно, но при массовом переборе дескрипторов (например, в picker с 50+ шрифтами) рекомендуется кэшировать результаты. Apple рекомендует выполнять матчинг один раз при загрузке экрана и сохранять массив дескрипторов.

Интеграция с Core Text и CTFontDescriptor

Core Text — низкоуровневый C-based фреймворк для работы с типографикой на iOS и macOS. Его аналог UIFontDescriptor — CTFontDescriptor, который предоставляет те же возможности на уровне Core Foundation. CTFontDescriptor используется в Core Text API для создания шрифтов, измерения текста и рендеринга сложной типографики. UIFontDescriptor по сути является Objective-C-обёрткой над CTFontDescriptor с расширенным набором атрибутов.

Toll-free bridging между UIFontDescriptor и CTFontDescriptor позволяет передавать дескрипторы между UIKit и Core Text без конвертации. Это критично для приложений, использующих кастомный рендеринг текста — например, текстовые редакторы на основе TextKit или редакторы кода с подсветкой синтаксиса. Пример: CTFontDescriptorCreateCopyWithAttribute создаёт копию дескриптора с добавленным атрибутом — аналог addingAttributes из UIFontDescriptor.

Key attribute kCTFontURLAttribute в CTFontDescriptor содержит URL шрифтового файла. Это позволяет определить, является ли шрифт системным или пользовательским. Для кастомных шрифтов URL ведёт в файл шрифта (.ttf или .otf), для системных — в системную директорию шрифтов. Данные через дескриптор доступны только для чтения; изменение файла шрифта через URL не поддерживается.

Для продвинутой типографики — кастомные лигатуры, контекстные замены, альтернативные глифы — используется CTFontDescriptorCopyAttribute с ключом kCTFontFeatureSettingsAttribute. Этот атрибут содержит массив словарей OpenType-фич, которые можно добавлять через дескриптор. По данным Apple Core Text Programming Guide, комбинирование UIFontDescriptor с Core Text даёт полный контроль над типографикой приложения.

Часто задаваемые вопросы

Чем Font Descriptor отличается от UIFont?

UIFont — это готовый к использованию шрифт, который рендерит текст. Font Descriptor — это описание шрифта, набор атрибутов, из которых можно создать UIFont. Один дескриптор может породить множество UIFont разных размеров.

Можно ли использовать Font Descriptor для кастомных шрифтов?

Да. Если шрифт зарегистрирован в системе (через Info.plist или Core Graphics), его дескриптор создаётся по семейству или по имени точно так же, как для системных шрифтов. Матчинг работает для любых зарегистрированных шрифтов.

Как получить имя шрифта из дескриптора?

Используйте descriptor.object(forKey: .visibleName), чтобы получить отображаемое имя, или descriptor.postscriptName для PostScript-имени. PostScript-имя используется при создании шрифта через UIFont(name:size:).

Что такое cascade list в Font Descriptor?

Cascade list — это массив вложенных дескрипторов, которые служат fallback-шрифтами. Если основной шрифт не содержит нужный символ, система последовательно проверяет шрифты из cascade list. Используется для поддержки эмодзи и CJK-символов.

Работает ли Font Descriptor в SwiftUI?

Да. SwiftUI поддерживает Font Descriptor через Font(descriptor:size:). SwiftUI-обёртка принимает UIFontDescriptor и создаёт шрифт SwiftUI, сохраняя все атрибуты дескриптора — кернинг, лигатуры и начертание.

Итоги

  • Font Descriptor — объект-описатель шрифта с атрибутами семейства, начертания, размера и типографических фич
  • Позволяет создавать UIFont из набора атрибутов с автоматическим шрифтовым матчингом
  • Поддерживает иммутабельную модификацию через addingAttributes, withSize, withSymbolicTraits
  • matchingFontDescriptors возвращает все доступные начертания для поиска и выбора шрифтов
  • Интегрируется с Core Text через toll-free bridging между UIFontDescriptor и CTFontDescriptor
  • Поддерживает Dynamic Type через предпочитаемые стили текста и масштабирование
  • Рекомендуется для адаптивной типографики, поддерживающей все версии iOS без проверки доступности шрифтов

Мы разработаем мобильное приложение под ключ

IT Sectr создаёт приложения для iOS и Android для стартапов и бизнеса с 2017 года. Мы проконсультируем вас и предложим наилучшее решение.

Обсудить проект

Читайте также