AI
prepair.app
Пройти інтерв'ю →
EnglishУкраїнськаРусский
🍏

Питання на співбесіді iOS розробника

Співбесіда iOS-розробника перевіряє систему типів Swift, розуміння ARC і вміння міркувати про стан інтерфейсу — плюс обов'язково трапиться питання, де retain cycle ховається на видноті. Нижче — питання, які ставлять найчастіше, кожне з еталонною відповіддю.

Junior · без досвіду / до 1 рокуMiddle · 2–4 роки досвідуSenior · 5+ років досвіду

Що запитують

Swift та опціонали
ARC і керування памʼяттю
SwiftUI та UIKit
Конкурентність: async/await, Combine, GCD
Архітектура і стан
Зберігання даних і мережа

12 реальних питань з відповідями

До кожного питання — еталонна відповідь, з якою можна порівняти свою.

1

Яку проблему розвʼязують опціонали і як безпечно їх розгортати?

Відповідь

Опціонал робить «значення може не бути» частиною типу, тому компілятор змушує обробити порожній випадок, а не падати в рантаймі, як це робить нульовий вказівник. Безпечне розгортання — це if let або guard let, коли значення потрібне далі, оператор ?? для значення за замовчуванням і опціональний ланцюжок, якщо цікавить лише успішний шлях. Force unwrap через ! — це обіцянка компілятору, що значення є: прийнятно для outlet-ів і помилок програміста, але ніколи для даних із мережі.

2

У чому різниця між struct і class у Swift? Що берете за замовчуванням?

Відповідь

Struct — значимий тип: присвоєння копіює його, спадкування немає, і за можливості він розміщується на стеку. Class — посилальний тип з ідентичністю, спадкуванням, deinit і накладними витратами ARC. Конвенція Swift — починати зі struct і переходити на class лише коли потрібна посилальна семантика: спільний змінюваний стан, сумісність з Objective-C або життєвий цикл, за яким треба спостерігати.

3

Як працює ARC і через що виникає retain cycle?

Відповідь

ARC рахує кількість сильних посилань на обʼєкт і звільняє його, коли лічильник обнуляється — це вставлені на етапі компіляції виклики retain/release, а не збирач сміття в рантаймі. Retain cycle виникає, коли два обʼєкти тримають сильні посилання один на одного і жоден лічильник не доходить до нуля: класика — вʼю-контролер володіє замиканням, що сильно захоплює self. Розривається через [weak self] або [unowned self] у списку захоплення.

4

Коли використовувати weak, а коли unowned?

Відповідь

Обидва не збільшують лічильник посилань. weak робить посилання опціональним і обнуляє його при звільненні обʼєкта, тому він безпечний, якщо інший обʼєкт може померти першим — делегати це стандартний приклад. unowned неопціональний і припускає, що обʼєкт переживе вас; якщо припущення порушиться, застосунок впаде. unowned беруть лише коли звʼязок життєвих циклів справді гарантований, у всіх сумнівних випадках — weak.

5

У чому різниця між @State, @Binding, @StateObject та @ObservedObject?

Відповідь

@State — локальний стан значимого типу, яким володіє вʼю; SwiftUI зберігає його поза структурою, тому він переживає перемальовування. @Binding — посилання на чужий стан із правом запису, саме так дочірнє вʼю змінює значення батьківського. @StateObject створює і володіє посилальним observable-обʼєктом та ініціалізується рівно один раз. @ObservedObject спостерігає за обʼєктом, яким володіє хтось інший — якщо поставити його там, де потрібен @StateObject, обʼєкт перестворюватиметься на кожному перемальовуванні й мовчки втрачатиме стан.

6

Як SwiftUI вирішує, що вʼю треба перемалювати?

Відповідь

Вʼю — це легка структура, що описує інтерфейс; SwiftUI перезбирає її body щоразу, коли змінюється прочитана нею залежність, потім порівнює результат із попереднім деревом і застосовує лише відмінності. Залежності — це ті property wrapper-и, які вʼю справді читає, плюс Environment. Проблеми продуктивності майже завжди йдуть від стану, піднятого зависоко по дереву: не повʼязана зміна інвалідує велике піддерево.

7

Що змінює async/await порівняно з completion-хендлерами та GCD?

Відповідь

async/await дозволяє читати асинхронний код зверху вниз, тому обробка помилок іде звичайним try/catch, немає «піраміди вкладеності» й забутих гілок завершення. Компілятор стежить, щоб await викликався в async-контексті, а структурна конкурентність привʼязує життя дочірніх задач до батьківської, тож скасування поширюється автоматично. GCD лишається актуальним для легасі й тонкого керування чергами, але новий код варто писати на async/await, залишивши Combine для справжніх потоків значень у часі.

8

Що таке escaping-замикання і навіщо це ключове слово?

Відповідь

Замикання вважається escaping, якщо воно зберігається і викликається вже після повернення з функції — наприклад, completion-хендлер мережевого запиту. Swift вимагає позначки @escaping, бо не-escaping замикання можна агресивніше оптимізувати і воно не може випадково сильно захопити self. Ця позначка ще й сигнал подумати про семантику захоплення: саме в escaping-замиканнях народжуються retain cycle.

9

Розберіть життєвий цикл UIViewController. Де розміщувати код верстки?

Відповідь

viewDidLoad виконується один раз після завантаження ієрархії вʼю і призначений для разового налаштування. viewWillAppear і viewDidAppear викликаються при кожному показі — туди йде те, що має повторюватися: оновлення даних, запуск анімації. Верстка, що залежить від фінальних розмірів, живе у viewDidLayoutSubviews, бо у viewDidLoad межі ще не остаточні — обчислення фреймів там дуже часта помилка, яка проявляється лише на іншому розмірі екрана.

10

Як обрати між Core Data, SwiftData і просто файлами?

Відповідь

Core Data виправдовує свою складність, коли дані реляційні та потрібні запити, лінива підвантаження і відстеження змін на великому графі обʼєктів. SwiftData — сучасна нативна для Swift обгортка над тим самим стеком, дефолт для нових застосунків на свіжих версіях ОС. Для десятка налаштувань беруть UserDefaults, а для кешу декодованих моделей звичайні Codable-файли або легке key-value сховище зрозуміліші, ніж повноцінний persistent container.

11

Як діагностувати повільний запуск або витік памʼяті?

Відповідь

Для часу запуску беруть шаблон App Launch в Instruments і дивляться, що виконується до першого кадру; звичайні винуватці — синхронна робота з диском чи мережею в didFinishLaunching і важкий граф залежностей, що збирається заздалегідь. Для витоків Memory Graph Debugger показує обʼєкти, які мали звільнитися, і того, хто на них ще посилається, — це напряму розкриває retain cycle. Інструмент Leaks ловить класичні витоки, але граф зручніший для циклів, бо він називає утримуюче посилання.

12

Що ви тестуєте в iOS, а що свідомо не тестуєте?

Відповідь

Юніт-тестами покривають бізнес-логіку, вʼю-моделі та чисті перетворення — усе, що має вхід і вихід і не залежить від UIKit. XCUITest беруть на невелику кількість критичних наскрізних сценаріїв на кшталт входу і покупки, бо UI-тести повільні та крихкі у великих обсягах. Зазвичай не окупається тестування поведінки фреймворків Apple і попіксельної верстки; снапшот-тести тут допомагають, але ламаються на кожній зміні версії ОС, тому їх тримають мало і свідомо.

🦎

Прочитати відповіді недостатньо

На співбесіді ти говориш вголос під тиском. Кем поставить ті самі питання, оцінить кожну відповідь і покаже, що саме підтягнути.

Пройти інтерв'ю iOS (Swift) →
Безкоштовно · 3 інтерв'ю на місяць

Інші спеціалізації

🔍QA Manual🤖QA AutomationJava Backend🐍Python Backend🐘PHP Backend🦫Go Backend🟢Node.js Backend⚛️React Frontend💚Vue Frontend🅰️Angular FrontendNext.js🤖Android (Kotlin)⚙️DevOps / SRE🗄️Data Engineer📈Business Analyst🎯Product Manager📋Project Manager🎨UI/UX Designer📣Marketing