RecallDeck
Направление

Подготовка к собеседованию — iOS-разработчик

Колода из 153+ карточек с вопросами для собеседования по направлению «iOS-разработчик» — по темам и уровню сложности, с возвратом ровно перед тем, как вы забудете. Посмотрите несколько карточек ниже, затем войдите, чтобы учить всё направление по расписанию в стиле Anki (SM-2).

153 карточки10 тем

Бесплатно · вход через GitHub · ваш прогресс остаётся с вами.

Что внутри

Все темы направления, сгруппированные так, как вы будете их учить.

Swift и система типов

12 карточек
Swift и типы

Память и ARC

9 карточек
Память и ARC

Многопоточность: GCD и Swift Concurrency

11 карточек
GCD и Swift Concurrency

UIKit и вёрстка

10 карточек
UIKit и вёрстка

SwiftUI

8 карточек
SwiftUI

Архитектура iOS-приложений

8 карточек
Архитектура

Сеть и хранение данных

9 карточек
Сеть и хранение

Производительность и инструменты

8 карточек
Производительность

Основы CS

43 карточки
Структуры данных и алгоритмы

Поведенческое интервью

35 карточек
Поведенческое интервью

Примеры вопросов

Несколько карточек из колоды — откройте ответ, затем войдите, чтобы учить весь набор по расписанию.

В чём реальные различия между struct и class в Swift?

Короткий ответ: struct — значимый тип: при присваивании и передаче в функцию значение копируется. class — ссылочный: переменные разделяют один экземпляр. Наследование, deinit и идентичность (===) есть только у классов; мутация структуры требует var и mutating-методов.

Подробно:

struct class
Семантика копия значения общая ссылка
Наследование ✗ (только протоколы)
deinit / ===
Мутация mutating + var всегда, даже через let
ARC нет retain/release (если нет ссылочных полей) есть
Инициализатор memberwise бесплатно пишешь сам
  1. По умолчанию — struct — предсказуемое копирование, нет гонок на общем состоянии, дешевле для ARC.
  2. Класс — когда нужна общая идентичность (кэш, сервис), наследование от NSObject-мира или deinit для освобождения ресурса.

⚠️ Частая ошибка: «структуры всегда живут на стеке». Нет: структура — поле класса, захвачена escaping-замыканием или упакована в экзистенциал с большим payload — живёт в куче. Value type определяет семантику копирования, а не место в памяти.

Как работает ARC и чем он отличается от сборщика мусора?

Короткий ответ: ARC — автоматический подсчёт ссылок: компилятор ещё на этапе компиляции вставляет вызовы retain/release вокруг работы с сильными ссылками. Объект умирает ровно в момент, когда счётчик ссылок падает до нуля — детерминированно и без пауз. Цена: циклы ссылок ARC собрать не может.

Подробно:

ARC Трассирующий GC
Кто решает компилятор: вставка retain/release рантайм: обход графа объектов
Момент освобождения детерминированный: счётчик = 0 недетерминированный, при сборке
Паузы нет stop-the-world / инкрементальные
Циклы не собирает — нужны weak/unowned собирает автоматически
Накладные расходы атомарные инкременты счётчика память под кучу + CPU на трассировку
  1. Компилятор, а не рантайм — retain вставляется при появлении новой сильной ссылки, release — при выходе из области видимости; оптимизатор выкидывает парные лишние вызовы.
  2. Детерминированный deinit — ресурс освобождается сразу, поэтому deinit пригоден для закрытия файлов, инвалидации таймеров, отписок.
  3. Плата — ретейн-циклы остаются ответственностью программиста.

⚠️ Частая ошибка: называть ARC «сборщиком мусора, только быстрее». ARC не сканирует память в рантайме — вся работа расставлена компилятором заранее, поэтому и пауз нет, и циклы сами не находятся.

Чем 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 невидимая работа: синк, индексация
  1. Очередь ≠ поток — serial очередь не владеет потоком: её задачи могут выполняться на разных потоках пула, но никогда одновременно.
  2. QoS решает планирование — системе QoS говорит, сколько CPU и энергии дать: .userInteractive — вне очереди, .background может подождать.

⚠️ Частая ошибка: «создал очередь — создал поток». Нет: тысячи очередей обслуживаются десятком потоков пула. А вот заблокировать много потоков через sync-ожидания — путь к thread explosion.

Жизненный цикл UIViewController: в каком порядке вызываются методы и что где делать?

Короткий ответ: loadView создаёт вью → viewDidLoad — одноразовая настройка (геометрии ещё нет!) → viewWillAppear — обновление перед каждым показом → viewWillLayoutSubviews/viewDidLayoutSubviews — единственные места, где фреймы валидны → viewDidAppear — анимации и тяжёлые старты → viewWillDisappear/viewDidDisappear.

Подробно:

loadView ─► viewDidLoad ─► viewWillAppear ─► viewWillLayoutSubviews
 (создать    (один раз)     (каждый показ)          │ layout pass
  view)                                             ▼
viewDidDisappear ◄─ viewWillDisappear ◄─ viewDidAppear ◄─ viewDidLayoutSubviews
                                          (на экране)      (фреймы валидны!)
  1. viewDidLoad — один раз за жизнь вью-контроллера: добавить сабвью, констрейнты, подписки. Размеров вью ещё нет.
  2. viewWillAppear — каждый показ: обновить данные, состояние баров.
  3. viewDidLayoutSubviews — bounds актуальны: скругления, пути CAShapeLayer, зависящая от размеров вёрстка. Вызывается многократно — без тяжёлой работы.
  4. viewDidAppear — вью на экране: запуск анимаций, дорогие операции, аналитика.
  5. viewWillDisappear/viewDidDisappear — остановить таймеры, сохранить состояние.

⚠️ Частая ошибка: читать view.bounds в viewDidLoad — там либо размер из сториборда, либо нули, но не реальная геометрия устройства. Всё, что зависит от размеров, живёт в viewDidLayoutSubviews.

Почему View в SwiftUI — структуры, и почему их постоянное пересоздание не дорого?

Короткий ответ: View — не вью в смысле UIKit, а лёгкое значение-описание: чертёж того, что показать. Структуры дёшево создавать и выбрасывать, поэтому SwiftUI свободно пересоздаёт их при каждом пересчёте body. Долгоживущая часть — render tree (attribute graph) — живёт за кулисами; именно там хранятся состояние и идентичность.

Подробно:

  1. Чертёж, а не экземпляр — UIView — тяжёлый объект с жизненным циклом и слоем; View-структура — пара полей и body, без ресурсов.
  2. Состояние снаружи — @State хранится фреймворком и привязан к идентичности вью в дереве, а не к структуре: структура умерла, значение осталось.
  3. Diffing — SwiftUI сравнивает новое описание со старым и минимально мутирует персистентное дерево; в пиксели уходит только разница.
body → View-значения (дёшево, пересоздаются каждый раз)
            │ diff

attribute graph / render tree (живёт долго:
@State, идентичность, анимации)

⚠️ Частая ошибка: приравнять «пересоздание структур» к «перерисовке UI». Создание описаний — копейки; дорогим бывает рендер, и он происходит только там, где diff нашёл изменение.

Почему Apple-овский MVC превращается в Massive View Controller и как разгрузить вью-контроллер, не меняя архитектуру?

Короткий ответ: Потому что в UIKit вью-контроллер по умолчанию — точка сборки всего: жизненный цикл вью, лейаут, data source таблицы, навигация и сетевые вызовы. Разгружается он выносом обязанностей в отдельные объекты — менять архитектуру для этого не обязательно.

Подробно:

  1. Диагноз — MVC у Apple не плох сам по себе; проблема в том, что «C» удобно принимает любой код, и без дисциплины вью-контроллер растёт до тысяч строк.
  2. Что выносить:
Обязанность Куда выносится
UITableViewDataSource / delegate отдельный объект-датасорс
Кусок экрана со своей логикой child view controller
Сеть, кэш, аналитика простые сервисные объекты
Конфигурация сабвью сами вью (configure(with:))
  1. Итог — вью-контроллер остаётся дирижёром: связывает сервисы, вью и навигацию, но не делает всю работу сам.

⚠️ Частая ошибка: отвечать «MVC — плохая архитектура, поэтому все ушли в MVVM». Плоха недисциплинированная реализация: без выноса обязанностей тот же перегруз повторится и с ViewModel.

Готовы закрепить навсегда?

Первая сессия — меньше минуты. Ваше будущее «я» на собеседовании скажет спасибо.

Вопросы об этом направлении

Как готовиться к собеседованию на «iOS-разработчик»?

Учите концепции, которые придётся объяснять, а не только те, что умеете кодить. Направление «iOS-разработчик» в RecallDeck даёт 153+ отобранных вопросов и возвращает каждый по расписанию в стиле Anki (SM-2) ровно перед тем, как вы забудете — чтобы на собеседовании ответы были под рукой.

Какие темы охватывает направление «iOS-разработчик»?

Направление «iOS-разработчик» разбито на ключевые области, которые реально проверяют на таких собеседованиях, — по темам и уровню сложности (Concept, Junior, Middle, Senior). Полный план и примеры вопросов можно посмотреть выше до входа.

Помогает ли интервальное повторение в подготовке к «iOS-разработчик»?

Да. Активно вспоминать ответ и честно себя оценивать — куда прочнее для памяти, чем перечитывать заметки. RecallDeck планирует каждую карту «iOS-разработчик» так, чтобы она вернулась перед моментом забывания: ежедневных повторений становится меньше, а знания держатся.

Направление «iOS-разработчик» бесплатное?

Да — направление «iOS-разработчик» и полный планировщик SM-2 бесплатны, с 20 новыми картами в день. Войдите через GitHub, и прогресс синхронизируется с аккаунтом. RecallDeck Pro ($5/мес или $29/год) поднимает дневной лимит и добавляет блиц-режим.

Другие направления

RecallDeckПодготовка к собеседованию на интервальных повторениях