Какой жизненный цикл UIView при создании кастомной вьюшки и какие методы жизненного цикла доступны
Что проверяют
Понимаете ли вы, в каком порядке UIKit вызывает методы кастомной вью и где место каждой настройке: создание сабвью, констрейнты, раскладка, отрисовка. Следом почти всегда спрашивают, почему layoutSubviews() нельзя вызывать напрямую и чем setNeedsLayout() отличается от layoutIfNeeded().
Как отвечать
Разложите жизнь вью по этапам:
- создание:
init(frame:)из кода,init?(coder:)из storyboard или xib. Второй инициализатор обязателен, общую настройку выносят в приватный метод и зовут из обоих; awakeFromNib(): только для вью из nib, к этому моменту аутлеты уже подключены;- иерархия:
willMove(toSuperview:)иdidMoveToSuperview(), затемwillMove(toWindow:)иdidMoveToWindow(). При уходе с экрана те же методы приходят сnil, здесь удобно запускать и останавливать анимации, таймеры, подписки; - цикл обновления: три прохода, констрейнты (
updateConstraints()), раскладка (layoutSubviews()), отрисовка (draw(_:)). Каждый запрашивается флагомsetNeedsUpdateConstraints(),setNeedsLayout(),setNeedsDisplay()и выполняется на ближайшем цикле, а не сразу; - размер:
intrinsicContentSizeиinvalidateIntrinsicContentSize(), если вью сама сообщает Auto Layout свой размер; - смена темы:
traitCollectionDidChange(_:)с iOS 17 устарел, вместо негоregisterForTraitChanges(_:handler:).
layoutIfNeeded() выполняет отложенную раскладку синхронно, поэтому его зовут внутри блока анимации, чтобы анимировать изменение констрейнтов.
Где спотыкаются
Называют removeFromSuperview() методом жизненного цикла. Это действие, которое вызываете вы, а уведомление о нём приходит в willMove(toSuperview:) с nil и в didMoveToSuperview().
Создают сабвью или добавляют констрейнты в layoutSubviews(). Метод вызывается много раз, и каждый вызов плодит новые объекты.
Переопределяют draw(_:) ради фона или скруглений. Даже пустой draw(_:) заставляет систему выделять буфер под отрисовку, а то же самое делается свойствами слоя.