В чем разница между заданием frame и использованием constraints (Auto Layout) в UIKit?

Ответ

Это два принципиально разных подхода к определению геометрии UIView.

Frame (Прямое задание рамки)

  • Что это: Прямое назначение прямоугольника (CGRect), определяющего относительно родительской системы координат:
    • origin (x, y) — положение верхнего левого угла.
    • size (width, height) — размеры.
  • Характеристики:
    • Статичный: Не адаптируется автоматически к изменениям размеров супервью (например, при повороте устройства).
    • Производительный: Минимальные накладные расходы на вычисления.
    • Пример:
      let customView = UIView()
      customView.frame = CGRect(x: 20, y: 100, width: 200, height: 44)
      parentView.addSubview(customView)

Constraints (Auto Layout — Ограничения)

  • Что это: Система декларативных правил (ограничений), которые описывают отношения между атрибутами видов (leading, top, width, centerX и т.д.). Система автоматически вычисляет frame на основе этих правил.
  • Характеристики:

    • Адаптивный и динамичный: Позволяет создавать интерфейсы, которые автоматически перестраиваются под разные размеры экранов, ориентации и контент.
    • Более сложный: Требует понимания системы приоритетов, активации/деактивации.
    • Пример (программно):

      let customView = UIView()
      customView.translatesAutoresizingMaskIntoConstraints = false
      parentView.addSubview(customView)
      
      NSLayoutConstraint.activate([
          customView.leadingAnchor.constraint(equalTo: parentView.leadingAnchor, constant: 20),
          customView.topAnchor.constraint(equalTo: parentView.topAnchor, constant: 100),
          customView.widthAnchor.constraint(equalToConstant: 200),
          customView.heightAnchor.constraint(equalToConstant: 44)
      ])
Сравнение и рекомендации: Аспект Frame-based Layout Auto Layout (Constraints)
Адаптивность Низкая, требует ручного пересчета Высокая, автоматическая подстройка
Сложность Низкая для простых случаев Высокая, требует понимания системы
Производительность Высокая Может быть ниже при сложных иерархиях
Когда использовать Кастомная анимация, draw(_:), высокопроизводительные scroll views, очень простые фиксированные layout'ы. Подавляющее большинство случаев — создание адаптивных интерфейсов.

Важно: Нельзя смешивать подходы для одного view без отключения translatesAutoresizingMaskIntoConstraints = false. Auto Layout в конечном счете всегда вычисляет frame view.

Ответ 18+ 🔞

А, ну вот, опять про эти ваши фреймы и констрейнты, блядь! Слушай, да это же как два разных способа поставить стул в комнате, ёпта!

Фрейм (Тупое тыканье пальцем в координаты)

Ну, представь, ты пришёл в пустую комнату и говоришь: «Стоять тебе, сука, стулу, ровно в метре от левой стены и в двух метрах от потолка, и быть тебе шириной в полметра, блядь!» Вот это и есть фрейм. Ты просто берёшь и впендюриваешь прямоугольник в пространство родителя.

  • Что это такое? Прямоугольник (CGRect), который ты тупо назначаешь. Там origin — это где верхний левый угол будет торчать, а size — ну, ширина-высота, чё уж тут.
  • Как оно?
    • Дубовое. Повернул телефон — а стул так и остался висеть в воздухе на тех же координатах, потому что система координат родителя съехала. Ручками всё пересчитывай, мудак.
    • Быстрое. Мозгов не надо, посчитал один раз — и всё, ебись оно конём.
    • Пример, чтоб понятнее было:
      let customView = UIView()
      customView.frame = CGRect(x: 20, y: 100, width: 200, height: 44)
      parentView.addSubview(customView)

      Всё, прилепил. Сиди, блядь, на месте.

Констрейнты (Auto Layout — Умные договорённости)

А это уже высший пилотаж, блядь. Ты не говоришь, где стоять. Ты говоришь: «Слушай, стул, ты у меня должен быть прижат левым боком к левой стене с отступом в 20 сантиметров. И сверху отступи от подоконника на 100. И шириной будь ровно 200, сука, ни сантиметром больше!» А система уже сама, хитрая жопа, вычисляет, где ему frame поставить, чтобы все эти условия выполнились.

  • Что это? Система правил-договорённостей между вьюхами. Не координаты, а отношения: «мой левый край равен твоему левому краю», «моя высота равна твоей высоте, поделённой на два».
  • Как оно?

    • Гибкое и адаптивное. Повернул телефон — система сама пересчитает, где чему быть, чтобы отношения сохранились. Вообще охуенно для разных экранов.
    • Сложное, блядь. Можно так наконстрейнить, что система разведёт руками и скажет «я нихуя не понял, конфликт», и всё встанет.
    • Пример (программно, чтоб жизнь мёдом не казалась):

      let customView = UIView()
      customView.translatesAutoresizingMaskIntoConstraints = false // ЭТО ВАЖНО, БЛЯДЬ! ГОВОРИМ "НЕ ПРЕВРАЩАЙ МОЙ ФРЕЙМ В КОНСТРЕЙНТЫ!"
      parentView.addSubview(customView)
      
      NSLayoutConstraint.activate([
          customView.leadingAnchor.constraint(equalTo: parentView.leadingAnchor, constant: 20),
          customView.topAnchor.constraint(equalTo: parentView.topAnchor, constant: 100),
          customView.widthAnchor.constraint(equalToConstant: 200),
          customView.heightAnchor.constraint(equalToConstant: 44)
      ])

      Выглядит как заклинание, но по сути — те же самые условия про стул.

Так что же выбрать, ёпта?

Смотри, вот тебе табличка, а то у тебя глаза уже стеклянные:

На что смотрим Фреймы (тупой способ) Констрейнты (умный способ)
Адаптивность Нулевая. Сам всё двигай, ленивая жопа. Выше крыши. Система сама всё пересчитает.
Сложность Для простого — легко. Для сложного — ад. Сначала нихуя не понятно, потом привыкаешь.
Скорость Быстро, потому что просто числа. Может тормозить, если наконстрейнишь целое полотно.
Когда юзать? Кастомная анимация, ручная отрисовка в draw(_:), какие-нибудь хитрые скролл-вьюхи, ну или если вьюха одна и навсегда. В 95% случаев, блядь! Весь современный адаптивный интерфейс.

И главное, запомни, как «Отче наш»: Нельзя для одной вьюхи одновременно тыкать её фреймом и вешать констрейнты, если не сказал translatesAutoresizingMaskIntoConstraints = false. А то система начнёт сама с собой спорить, и будет пиздец. В конечном счёте, Auto Layout — это такой хитрый калькулятор, который всё равно вычисляет тот самый итоговый frame. Просто делает это умно, а не в лоб.