UIKitJuniorCoding
Что такое Auto Layout и как создавать constraints программно по сравнению с Interface Builder?
Auto Layout вычисляет позицию и размер view через математические constraints. Программно используйте NSLayoutAnchor + NSLayoutConstraint.activate([…]), всегда устанавливая translatesAutoresizingMaskIntoConstraints = false.
Auto Layout — это система ограничений (constraints) в UIKit, которая вычисляет размер и позицию каждого view на основе набора математических соотношений. Вместо того чтобы задавать фиксированный frame, вы описываете отношения между атрибутами: левый край этого view = правый край того view + 8pt.
Ключевые классы и атрибуты
NSLayoutConstraint— базовый класс одного ограничения.NSLayoutAnchorи его подклассы:NSLayoutXAxisAnchor,NSLayoutYAxisAnchor,NSLayoutDimension— современный API (iOS 9+).UILayoutGuide— невидимый прямоугольник для группировки ограничений без лишних view.translatesAutoresizingMaskIntoConstraints— обязательноfalseдля любого view, которое вы добавляете программно.
Программное создание constraints через NSLayoutAnchor
import UIKit
class CardViewController: UIViewController {
private let cardView: UIView = {
let v = UIView()
v.backgroundColor = .systemBackground
v.layer.cornerRadius = 12
v.translatesAutoresizingMaskIntoConstraints = false // обязательно
return v
}()
private let titleLabel: UILabel = {
let l = UILabel()
l.font = .systemFont(ofSize: 17, weight: .semibold)
l.numberOfLines = 0
l.translatesAutoresizingMaskIntoConstraints = false
return l
}()
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(cardView)
cardView.addSubview(titleLabel)
setupConstraints()
}
private func setupConstraints() {
NSLayoutConstraint.activate([
// cardView: прижат к safe area с отступами 16pt
cardView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 16),
cardView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 16),
cardView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -16),
// titleLabel внутри cardView с padding 12pt
titleLabel.topAnchor.constraint(equalTo: cardView.topAnchor, constant: 12),
titleLabel.leadingAnchor.constraint(equalTo: cardView.leadingAnchor, constant: 12),
titleLabel.trailingAnchor.constraint(equalTo: cardView.trailingAnchor, constant: -12),
titleLabel.bottomAnchor.constraint(equalTo: cardView.bottomAnchor, constant: -12),
])
}
}
Сравнение с Interface Builder
- Interface Builder (Storyboard / XIB): constraints создаются мышью, хранятся в XML. Удобно для статичных экранов, но при конфликтах («ambiguous layout») IB показывает предупреждения жёлтым. Merge-конфликты в storyboard — боль при командной работе.
- Программно: полный контроль, легко переиспользовать через функции/подклассы, diff в git читаем. Но больше кода и нет визуального превью без запуска Xcode Preview / симулятора.
- NSLayoutConstraint.activate([…]): активировать нужно массивом — это эффективнее, чем вызывать
.isActive = trueпо одному (один проход по движку Auto Layout вместо N).
Content Hugging и Compression Resistance
Два приоритета, о которых часто забывают:
contentHuggingPriority— насколько view сопротивляется растяжению сверх intrinsicContentSize. По умолчанию 250.compressionResistancePriority— насколько view сопротивляется сжатию. По умолчанию 750.
// Иконка не должна растягиваться — поднимаем hugging
iconImageView.setContentHuggingPriority(.required, for: .horizontal)
// Заголовок может сжиматься меньше, чем подзаголовок
titleLabel.setContentCompressionResistancePriority(.defaultHigh, for: .horizontal)
Подводные камни
- Забыть
translatesAutoresizingMaskIntoConstraints = false— view получит автоматически сгенерированные constraints, которые будут конфликтовать с вашими. - Добавлять constraints до того, как view добавлен в иерархию (
addSubview) — runtime crash с неясным сообщением об ошибке. - Использовать
constraint.isActive = trueв цикле вместоNSLayoutConstraint.activate([…])— избыточные проходы движка, особенно заметно при большом числе constraints. - Не учитывать
safeAreaLayoutGuide— контент уходит под notch или home indicator на современных iPhone. - Держать ссылки на constraints для последующего изменения через
constraint.constant = …, а не деактивировать-активировать их попарно — деактивация/активация дороже измененияconstant. - Ambiguous layout в runtime — используйте
view.hasAmbiguousLayoutиview.exerciseAmbiguityInLayout()в Debug-сборке для диагностики. - Смешивать Auto Layout и прямое задание
frameв одном view — непредсказуемые результаты после следующего layout-прохода. - Не тестировать на Dynamic Type и разных размерах экрана — фиксированные высоты ломают layout при крупном шрифте.
Common mistakes
- Сводить «Auto Layout и как создавать constraints программно по сравнению с Interface Builder» к синтаксису и не объяснять reuse pool.
- Игнорировать жизненный цикл, основной поток или момент освобождения ресурсов в сценарии uikit-4.
- Выбирать API по привычке, не проверяя состояние, ошибки, доступность и платформенные ограничения.
What the interviewer is testing
- Формулирует точную модель для «Auto Layout и как создавать constraints программно по сравнению с Interface Builder» и подтверждает ее корректным примером.
- Умеет связать ответ с иерархия view controller, тестированием и отладкой на устройстве.
- Называет ограничения подхода uikit-4, включая производительность, память и сопровождение.