UIKit и рендеринг
UIKit — императивный, объектно-ориентированный фреймворк, на котором до сих пор работает большинство продакшн-приложений iOS, даже с ростом SwiftUI. Там, где SwiftUI описывает экран декларативно, UIKit заставляет строить его вручную — дерево объектов UIView, которым владеет UIViewController, изменяемое на месте и всегда на главном потоке. Понять его — значит держать в голове сразу три модели: иерархию view и цепочку откликов (responder chain), которая проводит через неё касания; конвейер Auto Layout и рендеринга, превращающий ограничения в пиксели; и жизненный цикл приложения, который решает, когда вашему коду вообще дадут выполниться.
Сквозная тема на собеседовании — невидимая машинерия под обычным на вид API. Ячейка не аллоцируется заново при каждом скролле — она переиспользуется из пула, и если её не сбросить, она нарисует не ту строку. Ограничение — не фиксированный frame, а одно уравнение в системе, которую решает движок раскладки. setNeedsLayout не раскладывает немедленно — он помечает view «грязной» для следующего прохода. Пропустите эти расписания — и получите тормоза, баги с чужой картинкой и неопределённое поведение при обращении к UIKit вне главного потока.
Карта темы
- Основы UIKit — иерархия view и
UIViewпротивCALayer, жизненный цикл view controller, responder chain, переиспользование ячеек и баг переиспользования, target-action и делегирование, правило главного потока. - Автолейаут и рендеринг — ограничения как линейная система, intrinsic content size, hugging против compression resistance, цикл layout/display,
frameпротивboundsи цена offscreen-рендеринга. - Жизненный цикл приложения — пять состояний приложения и их колбэки, сценовый жизненный цикл, фоновое выполнение, последовательность запуска и предупреждения о памяти.
Частые ошибки и ловушки
| Ошибка | Последствие |
|---|---|
Переиспользовать dequeued-ячейку, не сбросив её в prepareForReuse | Устаревший текст или картинка из другой строки рисуется на не той ячейке |
| Обращаться к UIKit вне главного потока | Неопределённое поведение — глюки, краши или ничего, случайным образом |
| Считать ограничение фиксированным frame | Нельзя понять, почему раскладка неоднозначна или переопределена |
Вызывать layoutSubviews напрямую | Обходит запланированный проход; используйте setNeedsLayout / layoutIfNeeded |
Скруглять углы через cornerRadius + masksToBounds на скроллящихся ячейках | Проход offscreen-рендеринга на кадр выбивает бюджет кадра |
Считать, что didFinishLaunching означает «UI на экране» | Настройкой окна владеют сценовые колбэки; работа на окно поставлена не туда |
Значение для собеседований
Вопросы по UIKit проверяют, знаете ли вы, что фреймворк делает за вас, а что оставляет вам. Кандидат, который скажет «ячейка достаётся из пула переиспользования, поэтому я сбрасываю её содержимое в prepareForReuse и защищаюсь от устаревшей асинхронной картинки», читается как человек, который отлаживал реальную таблицу. Сильнейшие ответы связывают симптом с механизмом — мигание чужой картинки с переиспользованием ячеек, рывки скролла с проходом offscreen-рендеринга, лог «constraints unsatisfiable» с переопределённой осью, краш с вызовом UIKit вне главного потока — а не перечисляют имена API. Всё здесь держится на двух правилах, которые стоит проговорить сразу: UIKit работает только на главном потоке, и почти ничего не происходит в момент запроса — оно планируется на следующий проход run loop.