Подготовка к собеседованию — iOS-разработчик
Колода из 153+ карточек с вопросами для собеседования по направлению «iOS-разработчик» — по темам и уровню сложности, с повторениями по вашим оценкам. Посмотрите несколько карточек ниже, затем выберите доступ, чтобы учить всё направление по расписанию в стиле Anki (SM-2).
Новым подписчикам месяца или года может быть доступно 7 дней бесплатно. Условия и сумму подтвердит страница оплаты.
С чего начать
Нужны основы Swift и опыт создания небольшого iOS-приложения. В общих алгоритмах есть примеры на Python; концепции применимы и в Swift, но их реализацию стоит потренировать отдельно.
Первый проход: Swift и система типов → Память и ARC. Начните с базовых вопросов в этих модулях, затем продолжайте по плану. К сложным и senior-вопросам возвращайтесь по требованиям вакансии; все карточки доступны с самого начала.
Общие темы могут входить в несколько направлений и сохраняют одну историю повторений. План ниже отмечает общие основы и профильные модули; выбирайте глубину под свою вакансию.
Что внутри
Все темы направления, сгруппированные так, как вы будете их учить.
Swift и система типов
12 карточекПрофильный модуль
Память и ARC
9 карточекПрофильный модуль
Многопоточность: GCD и Swift Concurrency
11 карточекПрофильный модуль
UIKit и вёрстка
10 карточекПрофильный модуль
SwiftUI
8 карточекПрофильный модуль
Архитектура iOS-приложений
8 карточекПрофильный модуль
Сеть и хранение данных
9 карточекПрофильный модуль
Производительность и инструменты
8 карточекПрофильный модуль
Основы CS
43 карточкиОбщие основы
Поведенческое интервью
35 карточекОбщие основы
Примеры вопросов
Несколько карточек из колоды — откройте ответ, затем выберите доступ, чтобы учить весь набор по расписанию.
В чём реальные различия между struct и class в Swift?
В чём реальные различия между struct и class в Swift?
Короткий ответ: struct — значимый тип, class — ссылочный тип с идентичностью. Обычная копируемая структура имеет семантику копирования; присваивание ссылки на класс разделяет экземпляр. Наследование и === относятся к классам. С Swift 5.9 существуют некопируемые структуры ~Copyable: они могут иметь deinit, но не допускают обычного копирования.
Подробно:
struct |
class |
|
|---|---|---|
| Семантика | значение; обычно Copyable |
общая ссылка |
| Наследование | нет, но есть протоколы | есть |
Идентичность === |
нет | есть |
deinit |
у некопируемых структур | есть |
| Мутация | для изменения хранимых полей нужны var и mutating-методы |
свойства var можно менять и через ссылку let |
| ARC | может применяться к ссылочным полям | управляет временем жизни экземпляра |
| Инициализатор | memberwise при выполнении условий синтеза | автоматический default/inherited — лишь при определённых условиях |
- Структура удобна для независимых значений. Копирование может быть оптимизировано, например через copy-on-write; ссылочные поля всё равно могут разделять изменяемое состояние.
- Класс нужен, когда важна общая идентичность или наследование. Безопасность потоков не следует автоматически ни из
struct, ни изclass. - Некопируемый ресурс можно моделировать
struct Resource: ~Copyable { deinit {} }: владение передают без копирования.
⚠️ Частая ошибка: «структуры всегда живут на стеке». Семантика значения не определяет размещение в памяти: структура может находиться внутри объекта в куче или быть упакована в экзистенциал.
Как работает ARC и чем он отличается от сборщика мусора?
Как работает ARC и чем он отличается от сборщика мусора?
Короткий ответ: ARC автоматически управляет сильными ссылками: компилятор вставляет и оптимизирует retain/release, а эти операции выполняются во время работы программы. Когда исчезает последняя сильная ссылка, объект может быть уничтожен. ARC не ищет недостижимые циклы, поэтому сильные циклы нужно разрывать явно.
Подробно:
| ARC | Трассирующий GC | |
|---|---|---|
| Механизм | подсчёт сильных ссылок, подготовленный компилятором | обход достижимого графа во время сборки |
| Освобождение | при последнем release; его точка зависит от времени жизни и оптимизации | по политике сборщика после установления недостижимости |
| Задержки | retain/release и синхронная цепочка deinit могут стоить времени |
зависят от реализации: паузы, инкрементальная или конкурентная работа |
| Циклы | недостижимый сильный цикл сам не собирается | недостижимые циклы могут быть собраны |
- Время жизни — последняя строка области видимости не обязательно совпадает с последним release. Оптимизатор может менять время жизни в разрешённых языком пределах; при необходимости используют
withExtendedLifetime. - Ресурсы —
deinitполезен для финальной очистки, но для обязательного своевременногоclose, отмены или отписки лучше явная операция и, где подходит,defer. Retain cycle может вообще не датьdeinitвыполниться. - Слабые ссылки —
weakне удерживает объект и обнуляется;unownedтребует доказательства, что объект ещё жив при обращении. Выбор следует из модели владения.
⚠️ Частая ошибка: «ARC работает только при компиляции и не имеет пауз». Во время выполнения остаются расходы на подсчёт ссылок и освобождение, а дорогой deinit может задержать поток.
Чем serial очередь отличается от concurrent, что такое main и global — и почему очередь это не поток?
Чем serial очередь отличается от concurrent, что такое main и global — и почему очередь это не поток?
Короткий ответ: Очередь — абстракция «список задач», а не поток: GCD мультиплексирует очереди по общему пулу потоков. Serial выполняет задачи строго по одной в порядке FIFO, concurrent запускает несколько параллельно. Main — единственная очередь с контрактом «выполняюсь на мейн-треде»; global — системные concurrent очереди, по одной на класс QoS.
Подробно:
| Очередь | Тип | Особенность |
|---|---|---|
DispatchQueue.main |
serial | привязана к мейн-треду; весь UI |
DispatchQueue.global(qos:) |
concurrent | системные, общие на приложение |
DispatchQueue(label:) |
serial по умолчанию | своя; attributes: .concurrent — параллельная |
| QoS | Для чего |
|---|---|
.userInteractive |
анимации, реакция на жест — «прямо сейчас» |
.userInitiated |
пользователь ждёт результат (открытие экрана) |
.utility |
долгая работа с прогрессом (загрузка файла) |
.background |
невидимая работа: синк, индексация |
- Очередь ≠ поток — serial очередь не владеет потоком: её задачи могут выполняться на разных потоках пула, но никогда одновременно.
- QoS решает планирование — системе QoS говорит, сколько CPU и энергии дать:
.userInteractive— вне очереди,.backgroundможет подождать.
⚠️ Частая ошибка: «создал очередь — создал поток». Нет: тысячи очередей обслуживаются десятком потоков пула. А вот заблокировать много потоков через sync-ожидания — путь к thread explosion.
Жизненный цикл UIViewController: в каком порядке вызываются методы и что где делать?
Жизненный цикл UIViewController: в каком порядке вызываются методы и что где делать?
Короткий ответ: loadView создаёт вью → viewDidLoad — одноразовая настройка (геометрии ещё нет!) → viewWillAppear — обновление перед каждым показом → viewWillLayoutSubviews/viewDidLayoutSubviews — единственные места, где фреймы валидны → viewDidAppear — анимации и тяжёлые старты → viewWillDisappear/viewDidDisappear.
Подробно:
loadView ─► viewDidLoad ─► viewWillAppear ─► viewWillLayoutSubviews
(создать (один раз) (каждый показ) │ layout pass
view) ▼
viewDidDisappear ◄─ viewWillDisappear ◄─ viewDidAppear ◄─ viewDidLayoutSubviews
(на экране) (фреймы валидны!)
viewDidLoad— один раз за жизнь вью-контроллера: добавить сабвью, констрейнты, подписки. Размеров вью ещё нет.viewWillAppear— каждый показ: обновить данные, состояние баров.viewDidLayoutSubviews— bounds актуальны: скругления, путиCAShapeLayer, зависящая от размеров вёрстка. Вызывается многократно — без тяжёлой работы.viewDidAppear— вью на экране: запуск анимаций, дорогие операции, аналитика.viewWillDisappear/viewDidDisappear— остановить таймеры, сохранить состояние.
⚠️ Частая ошибка: читать view.bounds в viewDidLoad — там либо размер из сториборда, либо нули, но не реальная геометрия устройства. Всё, что зависит от размеров, живёт в viewDidLayoutSubviews.
Почему View в SwiftUI — структуры, и почему их постоянное пересоздание не дорого?
Почему View в SwiftUI — структуры, и почему их постоянное пересоздание не дорого?
Короткий ответ: View — не вью в смысле UIKit, а лёгкое значение-описание: чертёж того, что показать. Структуры дёшево создавать и выбрасывать, поэтому SwiftUI свободно пересоздаёт их при каждом пересчёте body. Долгоживущая часть — render tree (attribute graph) — живёт за кулисами; именно там хранятся состояние и идентичность.
Подробно:
- Чертёж, а не экземпляр — UIView — тяжёлый объект с жизненным циклом и слоем; View-структура — пара полей и body, без ресурсов.
- Состояние снаружи — @State хранится фреймворком и привязан к идентичности вью в дереве, а не к структуре: структура умерла, значение осталось.
- Diffing — SwiftUI сравнивает новое описание со старым и минимально мутирует персистентное дерево; в пиксели уходит только разница.
body → View-значения (дёшево, пересоздаются каждый раз)
│ diff
▼
attribute graph / render tree (живёт долго:
@State, идентичность, анимации)
⚠️ Частая ошибка: приравнять «пересоздание структур» к «перерисовке UI». Создание описаний — копейки; дорогим бывает рендер, и он происходит только там, где diff нашёл изменение.
Почему Apple-овский MVC превращается в Massive View Controller и как разгрузить вью-контроллер, не меняя архитектуру?
Почему Apple-овский MVC превращается в Massive View Controller и как разгрузить вью-контроллер, не меняя архитектуру?
Короткий ответ: Потому что в UIKit вью-контроллер по умолчанию — точка сборки всего: жизненный цикл вью, лейаут, data source таблицы, навигация и сетевые вызовы. Разгружается он выносом обязанностей в отдельные объекты — менять архитектуру для этого не обязательно.
Подробно:
- Диагноз — MVC у Apple не плох сам по себе; проблема в том, что «C» удобно принимает любой код, и без дисциплины вью-контроллер растёт до тысяч строк.
- Что выносить:
| Обязанность | Куда выносится |
|---|---|
UITableViewDataSource / delegate |
отдельный объект-датасорс |
| Кусок экрана со своей логикой | child view controller |
| Сеть, кэш, аналитика | простые сервисные объекты |
| Конфигурация сабвью | сами вью (configure(with:)) |
- Итог — вью-контроллер остаётся дирижёром: связывает сервисы, вью и навигацию, но не делает всю работу сам.
⚠️ Частая ошибка: отвечать «MVC — плохая архитектура, поэтому все ушли в MVVM». Плоха недисциплинированная реализация: без выноса обязанностей тот же перегруз повторится и с ViewModel.
Готовы лучше запоминать?
Посмотрите пример, выберите направление и настройте регулярную практику под свою подготовку.
Вопросы об этом направлении
Как готовиться к собеседованию на «iOS-разработчик»?
Учите концепции, которые придётся объяснять, а не только те, что умеете кодить. Направление «iOS-разработчик» в RecallDeck даёт 153+ отобранных вопросов и возвращает каждый по расписанию в стиле Anki (SM-2), основанному на ваших оценках — чтобы тренировать вспоминание и объяснение. Дополняйте повторения кодингом и пробными собеседованиями.
Какие темы охватывает направление «iOS-разработчик»?
Направление «iOS-разработчик» разбито на ключевые области, которые реально проверяют на таких собеседованиях, — по темам и уровню сложности (Concept, Junior, Middle, Senior). Полный план и примеры вопросов можно посмотреть выше до входа.
Помогает ли интервальное повторение в подготовке к «iOS-разработчик»?
Да. Активное вспоминание и честная самооценка помогают закреплять знания. RecallDeck назначает повторения карт по направлению «iOS-разработчик» на основе ваших оценок: знакомые карты возвращаются реже, а сложные получают больше практики.
Можно попробовать направление «iOS-разработчик» до оплаты?
Новым подписчикам месячного или годового тарифа может быть доступен пробный период семь дней со всем направлением «iOS-разработчик» и всеми функциями. Право на него и сумму подтвердит страница оплаты; при повторной подписке списание может быть сразу. Отмените подписку онлайн до конца пробного периода, чтобы избежать первого списания. У вечного доступа пробного периода нет.