Что такое приоритет ограничения (Constraint Priority) в Auto Layout (iOS)?

«Что такое приоритет ограничения (Constraint Priority) в Auto Layout (iOS)?» — вопрос из категории UIKit, который задают на 10% собеседований IOS Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Приоритет ограничения (Constraint Priority) — это числовое значение (UILayoutPriority), которое определяет важность ограничения в системе Auto Layout. Оно используется для разрешения конфликтов, когда не все заданные ограничения могут быть выполнены одновременно.

  • Диапазон: от 1 до 1000.
  • Required (Обязательное): Приоритет 1000. Система должна выполнить это ограничение. Конфликт обязательных ограничений приводит к ошибке макета (break).
  • Optional (Необязательное): Приоритет < 1000 (например, 750, 250). Система пытается выполнить ограничение, но может его нарушить в пользу более приоритетного.

Стандартные приоритеты:

  • .required = 1000
  • .defaultHigh = 750 (Высокий, например, для contentHuggingPriority)
  • .defaultLow = 250 (Низкий, например, для contentCompressionResistancePriority)

Как работает: При конфликте Auto Layout создает систему уравнений. Приоритеты влияют на «жесткость» этих уравнений. Ограничения с более высоким приоритетом удовлетворяются в первую очередь.

Пример на Swift:

let view = UIView()
view.translatesAutoresizingMaskIntoConstraints = false

// 1. Ограничение ширины 200 (высокий приоритет)
let widthConstraint = view.widthAnchor.constraint(equalToConstant: 200)
widthConstraint.priority = .defaultHigh // 750

// 2. Ограничение ширины <= 300 (низкий приоритет)
let maxWidthConstraint = view.widthAnchor.constraint(lessThanOrEqualToConstant: 300)
maxWidthConstraint.priority = .defaultLow // 250

// 3. Ограничение «растянуть по ширине родителя» (обязательное)
let leadingConstraint = view.leadingAnchor.constraint(equalTo: superview.leadingAnchor)
let trailingConstraint = view.trailingAnchor.constraint(equalTo: superview.trailingAnchor)
// Приоритет по умолчанию .required (1000)

NSLayoutConstraint.activate([
    widthConstraint, maxWidthConstraint, leadingConstraint, trailingConstraint
])

В этом сценарии:

  1. Обязательные ограничения leading и trailing выполнятся, пытаясь растянуть view на всю ширину.
  2. Это вступит в конфликт с widthConstraint = 200.
  3. Система сравнит приоритеты: .required (1000) у растяжения против .defaultHigh (750) у фиксированной ширины.
  4. Будет нарушено ограничение с приоритетом 750 (widthConstraint), и ширина станет больше 200.
  5. Ограничение maxWidthConstraint (приоритет 250) также будет нарушено, если итоговая ширина превысит 300.