В чем разница между viewWillLayoutSubviews и viewDidLayoutSubviews в iOS?
Что проверяют
Понимаете ли вы, что один вызывается до расчёта раскладки, а другой после, и знаете ли, что оба вызываются многократно.
Как отвечать
viewWillLayoutSubviews вызывается перед тем, как контроллер разложит подпредставления. На этот момент размеры дочерних элементов ещё не пересчитаны, а вот bounds самого корневого представления уже актуален. Здесь уместно менять то, что влияет на раскладку: константы ограничений, флаги, размеры вложенного слоя.
viewDidLayoutSubviews вызывается после: все размеры и позиции посчитаны и достоверны. Здесь берут итоговую геометрию: скругление по половине высоты, настройка градиента под фактический размер слоя (слои не участвуют в Auto Layout и не подстраиваются сами), расчёт вставок прокрутки.
Ключевое, что стоит подчеркнуть: оба вызываются много раз за жизнь экрана, а не однажды. Поворот, появление клавиатуры, изменение размера ячейки, любое setNeedsLayout приводят к новому проходу. Поэтому там нельзя ничего создавать, подписываться или запускать анимации: получите десятки подписок и мигание.
Отсюда типичное распределение: разовая настройка в viewDidLoad, работа с фактическими размерами в viewDidLayoutSubviews, изменение параметров раскладки в viewWillLayoutSubviews.
Ещё одна ловушка: изменение ограничений внутри viewDidLayoutSubviews запускает новый проход раскладки, и при неаккуратности получается бесконечный цикл.
Где спотыкаются
Считают размеры в viewDidLoad, где они ещё не окончательные.
Создают подписки и объекты в методах раскладки.
Меняют ограничения в viewDidLayoutSubviews и получают зацикливание.
Настраивают слой один раз и удивляются, что после поворота градиент не совпадает с новым размером.