Вопросы на собеседовании: iOS-разработчик
100 реальных вопросов с образцовыми ответами и пояснениями для уровня Senior.
Смотреть пример резюме: iOS-разработчик →Тренировка флешкарточками
Интервальное повторение · Hunter Pass
Вопросы
Я оставлю UIKit coordinator владельцем flow и встрою SwiftUI checkout через одну фабрику UIHostingController.
- Фабрика принимает типизированный checkout input и возвращает действия paid, cancelled или authenticationRequired, не раскрывая SwiftUI state в UIKit.
- Один @Observable model или TCA store владеет состоянием checkout; hosting controller связывает только navigation bar, dismissal и environment dependencies.
- До добавления второго SwiftUI flow я проверю push, modal dismissal, вход по deep link и освобождение памяти после 20 повторных показов.
Зачем это спрашивают: Интервьюер проверяет, сохраняет ли внедрение SwiftUI одного владельца навигации и состояния на границе фреймворков.
Я использую UIViewControllerRepresentable с Coordinator, который владеет delegate bridge и не помещает lifecycle capture в updateUIViewController.
- makeUIViewController создаёт controller один раз, а updateUIViewController применяет только изменившуюся конфигурацию, например zoom или выбранную камеру.
- Coordinator преобразует delegate callbacks в типизированные actions и не удерживает parent wrapper или controller в цикле.
- dismantleUIViewController останавливает session и очищает delegate; 50 показов и закрытий должны сохранять стабильное число объектов.
Зачем это спрашивают: Сильный ответ соблюдает identity representable, ownership delegate и teardown вместо пересоздания дорогого UIKit controller при каждом update.
Я выберу TCA, потому что при такой сложности явные переходы state и cancellation effects окупают дополнительные правила.
- Address, quote, payment и submission останутся единым feature state со scoped child reducers вместо четырёх view models, меняющих общие services.
- Каждый запрос получает cancellation ID, а смена адреса отменяет устаревший quote до запуска нового effect.
- Выбор подтверждают reducer tests для 9 actions, устаревших responses и double-submit, а простой receipt screen остаётся на обычном SwiftUI или MVVM.
Зачем это спрашивают: Интервьюер оценивает выбор паттерна по конкретной сложности state и side effects, а не по предпочтению.
Я добавлю debounce для query и сделаю search effect cancellable с одним стабильным cancellation ID.
- Action queryChanged сразу обновляет локальный state, затем ждёт 300 мс на управляемых clock перед запросом результатов.
- cancelInFlight отменяет предыдущий effect при новом query, а response action несёт query или request ID для последней проверки на устаревание.
- TestStore с TestClock проходит 299 и 1 мс и доказывает, что ввод пяти символов создаёт один запрос и игнорирует отменённый response.
Зачем это спрашивают: Сильный ответ делает timing, cancellation и защиту от устаревшего response детерминированными в коде и тестах.
Я сохраню типизированный route state вне views и построю NavigationStack path из этого единственного источника истины.
- Route enum хранит только стабильные identifiers, а validation преобразует deep link в шаги 1-3 и отвергает отсутствующие prerequisites.
- Scene storage хранит versioned codable snapshot маршрута, но чувствительные form values остаются в feature store или Keychain.
- Тесты покрывают cold launch, malformed links, back navigation и смену schema version, чтобы restoration не создавала невозможный path.
Зачем это спрашивают: Интервьюер проверяет state-driven navigation, валидированные deep links и versioned restoration вместо императивных push.
Я разорву циклы на принадлежащих владельцам contracts и оптимизирую измеренные high-churn dependency paths, не объединяя все 42 targets вслепую.
- Xcode build timing и package graph найдут shared targets, изменение которых инвалидирует 30 и более dependents.
- Cross-feature route и result protocols перейдут в узкие interface targets, а app composition target предоставит implementations и orchestration.
- CI запретит cycles и неразрешённые imports; изменение останется, если типовой incremental build станет короче 90 секунд без лишнего package overhead.
Зачем это спрашивают: Сильный ответ рассматривает modularization как проектирование dependency graph с измеримым результатом сборки.
Я опубликую capabilities под потребителя вместо превращения конкретного 18-методного service в межпакетный API.
- Checkout получает CurrentAccountProviding и AddressUpdating, а profile только более широкие mutations, которыми реально владеет.
- Domain values на границе будут Sendable structs, а transport DTO, URLSession и persistence models останутся internal.
- Contract tests запускаются для live implementation и fakes, а composition root адаптирует один AccountService к каждому узкому protocol.
Зачем это спрашивают: Интервьюер оценивает interface segregation, package visibility и безопасные для concurrency boundary models.
Я отделю стабильные design primitives от изменчивых product components и уберу umbrella imports из feature code.
- Color, typography, spacing и пять зрелых controls образуют низкоизменчивый DesignCore target с намеренно малым public API.
- Product-specific banners и experiments остаются в своих features, а не попадают в SharedUI после второго использования.
- Я сравню 20 incremental builds до и после, требуя меньшего invalidation time без роста launch time или дублирования resources.
Зачем это спрашивают: Сильный ответ использует частоту изменений и ownership для сокращения build invalidation вместо ещё одного общего package.
Я определю одно типизированное feature dependency value и передам его в package entry point из app composition root.
- У обязательных services нет скрытого production singleton fallback, поэтому отсутствие зависимости проявится при создании, а не во время checkout.
- Clock и UUID получают управляемые implementations, а networking и analytics раскрывают только используемые feature operations.
- Тест создаёт feature с четырьмя fakes менее чем за 10 мс, а package code содержит ноль обращений к global container.
Зачем это спрашивают: Интервьюер проверяет явный dependency ownership и детерминированные seams без скрытого service locator.
Я объявлю resources в target-владельце и буду получать их через Bundle.module внутри package.
- Localized catalogs и assets обрабатываются как process, а JSON копируется только когда нужно сохранить структуру каталога или исходные bytes.
- Public feature API возвращает semantic image и string values, не раскрывая bundle paths потребителям.
- Package tests загружают одну localized string в двух locales, декодируют fixture и проверяют одну копию каждого resource в release archive.
Зачем это спрашивают: Сильный ответ знает ownership ресурсов SPM и не связывает consumers со структурой package bundle.
Я раскрою feature factory и типизированные inputs и outputs с отдельными hosting adapters над одной реализацией state и domain.
- SwiftUI adapter возвращает feature view, а UIKit adapter оборачивает тот же view в UIHostingController и владеет containment details.
- Availability-specific поведение остаётся в adapters, поэтому domain target не импортирует UIKit и не ветвится по версиям iOS.
- Integration tests прогоняют три одинаковых user journeys через оба hosts и проверяют одинаковые actions, navigation results и deallocation.
Зачем это спрашивают: Интервьюер проверяет, остаётся ли переиспользуемая feature logic независимой от UIKit и SwiftUI hosts.
Я сначала измерю cell updates и identity, потому что сам по себе SwiftUI hosting не доказывает источник bottleneck.
- Time Profiler и Core Animation разделят body work, Auto Layout, image decoding и применение diffable snapshot в одной scroll trace.
- Stable item IDs и готовые row models предотвращают замену всего subtree, а image work не выполняется в cell configuration.
- Я сохраню границу, если p95 hitch duration будет короче одного кадра 16,67 мс на целевом устройстве после 10 одинаковых scroll runs.
Зачем это спрашивают: Сильный ответ измеряет seam UIKit и SwiftUI и исправляет identity или размещение работы до переписывания.
Я уберу strong cycle на ребре closure и явно задам lifetime completion.
- Controller владеет closure, поэтому strong capture self создаёт controller to closure to controller; memory graph должен показать именно этот path.
- Если completion не обязана выполняться после dismissal, захвачу self weakly; если обязана, перенесу работу к более долгоживущему owner.
- One-shot callbacks очищаются после вызова, а тест 30 раз показывает и закрывает controller с нулём оставшихся instances.
Зачем это спрашивают: Интервьюер проверяет рассуждение по ARC graph и соответствие weak capture требуемой семантике lifetime.
Я выберу weak, если дизайн не доказывает, что parent живёт дольше каждого обращения к ссылке child.
- weak безопасно становится nil после освобождения parent и подходит для asynchronous completion или teardown, которые могут прийти поздно.
- unowned убирает optional handling, но падает при доступе после deallocation, поэтому годится лишь при строгом инварианте общего lifetime.
- Lifecycle test освобождает parent до delayed callback child; если такая последовательность допустима, unowned неверен по конструкции.
Зачем это спрашивают: Сильный ответ выбирает weak или unowned по доказанному lifetime invariant, а не по стилю.
Task сильно удерживает view model на время load, поэтому я дам task явного owner и отменю её при завершении feature.
- Сохраню Task handle, отменю при replacement или teardown и проведу cancellation в URLSession вместо поглощения CancellationError.
- Одного weak capture мало, если guard let self создаёт strong reference до пятисекундного await; я сокращу strong lifetime или перенесу durable work в service.
- Тест закрывает экран через 100 мс, проверяет cancellation запроса и deallocation view model за один run-loop turn.
Зачем это спрашивают: Интервьюер проверяет closure capture через suspension и явный ownership unstructured tasks.
Я проверю каждую регистрацию по тому, кто кого удерживает и где заканчивается её полезный lifetime.
- Block timer удерживает closure, stored AnyCancellable удерживает subscription chain, и оба могут замкнуть цикл через self.
- Delegate properties будут weak, когда delegate не владеет source; selector-based NotificationCenter observers всё равно требуют осмысленного teardown, даже если auto-removal предотвращает crash.
- Teardown инвалидирует timer, отменяет subscriptions и очищает callbacks, а memory test из 50 циклов возвращает число экранов к baseline.
Зачем это спрашивают: Сильный ответ разбирает четыре разных механизма lifetime вместо механического weak self.
Я ограничу временные Objective-C objects вложенными autorelease pools и буду обрабатывать импорт измеренными batches.
- Instruments Allocations покажет, накапливаются ли bridged NSString, NSDictionary или formatter objects до освобождения внешнего run loop.
- Обработаю 500 или 1 000 records внутри autoreleasepool blocks, сохраню результат и освобожу batch до чтения следующего.
- Настрою batch size так, чтобы peak memory была ниже 300 МБ, а импорт 80 000 records не замедлился более чем на 10%.
Зачем это спрашивают: Интервьюер проверяет взаимодействие ARC с autoreleased Objective-C objects и количественный batching.
Нет, value semantics гарантирует независимо наблюдаемые значения, а не constant-time copy для каждого custom type.
- Data и стандартные collections часто используют copy-on-write, поэтому неизменённые copies делят storage до mutation.
- Custom struct с большим reference-backed buffer требует явного copy-on-write box и isKnownUniquelyReferenced перед изменением.
- Я измерю allocations для 1 000 проходов и сохраню value design, только если mutation copies возникают на задуманной границе ownership.
Зачем это спрашивают: Сильный ответ отделяет value semantics от стоимости реализации и знает, когда нужен custom copy-on-write.
Я оставлю UI state изолированным на MainActor, но вынесу decoding в non-main Sendable service boundary.
- Await URLSession не блокирует actor, но synchronous JSONDecoder после возобновления всё равно может занять MainActor.
- Decoder service возвращает Sendable domain snapshot, после чего view model выполняет на MainActor только финальное присваивание state.
- Main Thread Checker и signposts должны показать отсутствие main-thread blocks дольше 16 мс и одинаковый результат в 100 fixture runs.
Зачем это спрашивают: Интервьюер проверяет, не путает ли кандидат actor isolation с местом выполнения тяжёлой synchronous CPU work.
Я считаю await точкой reentrancy и зарезервирую или версионирую stock до выхода из actor isolation.
- Один вариант атомарно переводит единицу в reserved state, затем возвращает её при failure или cancellation authorization.
- Другой сохраняет version и повторно проверяет её после await, но тогда commit проходит лишь у одного покупателя, а второму нужен определённый payment reversal.
- Детерминированный тест приостанавливает обе authorizations в одной точке и доказывает, что ровно один order достигает committed state.
Зачем это спрашивают: Сильный ответ понимает actor reentrancy и сохраняет бизнес-инвариант через suspension.
Закрытые вопросы
- 21
Gallery должна скачать и downsample 200 images, но запуск всех child tasks сразу вызывает memory spike. Как применить structured concurrency?
concurrencyswiftmemory - 22
SwiftUI search screen запускает новый async request для каждого query и показывает устаревшие results после быстрого ввода. Как связать работу со state?
asyncswiftconcurrency - 23
Delegate API может вызвать success, failure или не вызвать callback после cancellation. Как обернуть его continuations?
delegationapiresilience - 24
Swift 6 запрещает передавать legacy mutable ImageCache class в две tasks, потому что он не Sendable. Как исправить правильно?
swift - 25
Legacy cache использует concurrent DispatchQueue с barrier writes и вызывается из нового async code. Нужно ли сразу заменить его actor?
asyncconcurrencycaching - 26
Background queue вызывает DispatchQueue.main.sync, пока main thread ждёт завершения этой background work. Почему приложение зависает?
concurrencydata-structures - 27
User-initiated task ждёт за 5 000 utility-priority operations на одном actor, задерживая реакцию на tap на две секунды. Как исправить priority problem?
concurrency - 28
Bluetooth callback выдаёт 100 samples в секунду, а UI потребляет только 10. Как раскрыть его через AsyncStream без безграничного роста памяти?
asynccallbacksconcurrency - 29
Profile screen одновременно нужны account, permissions и avatar, а gallery загружает переменное число albums. Какие concurrency primitives подходят?
concurrency - 30
ProMotion feed нацелен на 120 Гц, но p95 frame time равен 14 мс, и пользователи видят hitches. Какой budget и tools вы используете?
- 31
Изменение одного unread-count заставляет SwiftUI dashboard из 12 cards пересчитывать body каждой card. Как сузить invalidation?
swiftuiswift - 32
Feed загружает 12-мегапиксельные JPEG для thumbnails 120 на 120 points и достигает 900 МБ памяти. Как перестроить image handling?
memory - 33
Применение diffable snapshot для 10 000 items блокирует main thread на 180 мс, хотя изменилось лишь 20 rows. Что изменить?
snapshotconcurrency - 34
Cold launch на iPhone трёхлетней давности вырос с 1,2 до 2,9 секунды после добавления analytics и feature SDK. Как вернуть budget?
- 35
Переиспользуемая UIKit card создаёт 70 Auto Layout constraints, а layoutSubviews занимает 9 мс на каждую видимую cell. Что проверить?
uikitlayoutautolayout - 36
Экран ощущается медленным, но Time Profiler показывает несколько небольших затрат и ни одной функции на 100 мс. Как найти critical path?
schedulingcommunication - 37
@Observable app model содержит 40 properties и передаётся каждому экрану через Environment. Какую границу state вы создадите?
- 38
Parent создаёт @Observable editor model, а три child SwiftUI views должны менять её поля без создания copies. Какие wrappers использовать?
swiftuiswift - 39
Combine type-ahead search отправляет пять requests на пять символов и иногда показывает первый response последним. Какие operators подходят?
combine - 40
Combine pipeline получает 500 sensor values в секунду, тратит 4 мс на transform каждого и начинает отставать. Как обработать pressure?
soft-skillsci-cdcombine - 41
Background Core Data import передаёт NSManagedObject instances на MainActor и периодически падает. Что должно пересекать границу вместо них?
core-data - 42
Импорт 100 000 Core Data records занимает 90 секунд и увеличивает память до 1,1 ГБ. Как сократить оба показателя?
core-datamemory - 43
Новая offline notes feature нацелена на iOS 17+, хранит 50 000 records и позже может потребовать CloudKit. Вы выберете SwiftData или Core Data?
core-dataswift - 44
News app получает один и тот же feed на 2 МБ при каждом launch, хотя сервер возвращает cacheable ETag headers. Как настроить URLSession caching?
cachingconfignetworking - 45
Payment request завершился timeout после возможного списания карты сервером. Должен ли URLSession client автоматически повторить его?
resiliencenetworking - 46
Upload видео на 600 МБ должен продолжаться после suspension или termination приложения. Какой дизайн URLSession подходит?
designnetworking - 47
Двадцать requests одновременно получают 401 после expiration access token, вызывая 20 refresh calls и повторные failures. Как сериализовать refresh?
tokensserialization - 48
Async test view model использует Task.sleep и периодически падает в CI. Как сделать время и completion детерминированными?
asyncconcurrency - 49
Reducer запускает request на appear, отменяет на dismiss и должен игнорировать поздний response. Какие tests доказывают поведение?
testing - 50
Core Data repository и URLSession client нужно тестировать без реального server и постоянного user store. Какие test boundaries вы создадите?
core-datanetworking - 51
Image feed начинает с 180 МБ и достигает 720 МБ после 12 минут scrolling, затем получает memory warning. Как найти и остановить рост?
memory - 52
Каждый показ checkout screen оставляет ещё 18 МБ, и память растёт на 180 МБ после десяти dismissals. Как найти retain cycle?
memory - 53
После просмотра 20 видео в памяти остаются 20 AVPlayer instances и 40 player items, хотя все экраны закрыты. Что проверить?
- 54
Background import 120 000 records достигает 1,6 ГБ и завершается системой на устройствах с 3 ГБ, но Instruments показывает мало долгоживущих domain objects. Как снизить память?
memoryprofiling - 55
SwiftUI detail flow добавляет 25 МБ при каждом push и pop, view structs исчезают, но feature store остаётся. Как это отлаживать?
swiftmlopsswiftui - 56
Пятикратное открытие и закрытие support chat оставляет пять WKWebView instances и добавляет 90 МБ за визит. Где вероятная ownership trap?
ownership - 57
C-библиотека изображений добавляет около 6 МБ за каждый export, но Swift Memory Graph не показывает retaining Swift objects. Как расследовать?
memoryswift - 58
Crash-free users падают с 99,92% до 98,7%, а top crash имеет EXC_BAD_ACCESS в objc_retain и hexadecimal frames. Какова первая последовательность анализа?
- 59
Force unwrap в parsing receipt вызывает 34% всех crashes, но только для одной locale и invoices старше 2022 года. Как исправить и проверить?
- 60
Crash Array index out of range происходит 70 раз на миллион sessions, пока diffable list получает background updates. Как его воспроизвести?
indexessessions - 61
Release падает только на iOS 16 с unrecognized selector после добавления framework, собранного новым SDK. Как локализовать compatibility fault?
- 62
Crash reports показывают stack overflow после изменения settings с 1 400 повторяющимися observer frames. Как разорвать recursion?
recursionmemory - 63
App исчезает во время image editing без обычного crash stack, а MetricKit показывает peak memory около 2,1 ГБ. Как подтвердить out-of-memory termination?
memorymonitoring - 64
MetricKit показывает watchdog terminations на launch, а sample main thread содержит synchronous database migration на 18 секунд. Что изменить?
databasemigrationsmonitoring - 65
Tap по Pay замораживает UI на 1,8 секунды, хотя сам request занимает лишь 120 мс. Как найти main-thread blocker?
communicationconcurrency - 66
Feed на 120 Гц показывает p95 frame time 22 мс после выпуска нового image effect. Как найти источник jank?
- 67
Одно событие typing заставляет SwiftUI form из 60 fields пересчитываться 45 мс и терять видимые keystrokes. Как сузить update?
formsswiftuiswift - 68
Rotation сложного UIKit dashboard блокирует main thread на 320 мс и пишет unsatisfiable constraints. Что проверить первым?
uikitautolayoutconcurrency - 69
Открытие History блокирует scrolling на 260 мс, пока Core Data получает 40 000 rows на view context. Как вернуть responsiveness?
responsivecore-data - 70
Animation раскрытия card работает на 30 FPS на старых devices после добавления shadows и masks. Как решить, что упростить?
- 71
Touches не отвечают 900 мс при отправке analytics event, хотя dispatch в SDK выглядит asynchronous. Как доказать скрытое ожидание?
asyncconcurrency - 72
После миграции callbacks на async/await shared Dictionary падает с EXC_BAD_ACCESS примерно раз на 200 000 requests под нагрузкой. Как исправить race?
asynccallbacksconcurrency - 73
Auth actor проверяет expiration token, ожидает refresh, а три callers перезаписывают state разными refresh results. Что произошло?
asyncconcurrencytokens - 74
Continuation bridge падает в debug с 'tried to resume more than once', когда cancellation конкурирует с delegate callback. Как исправить?
callbacksprotocolsresilience - 75
Core Data object, созданный в background task, читается на MainActor и падает только во время тяжёлого sync. Как убрать concurrency violation?
core-dataconcurrency - 76
Task.detached обновляет @Published state в ObservableObject и вызывает редкие failures 'Publishing changes from background threads'. Что изменить?
concurrency - 77
AsyncStream wrapper продолжает отдавать location updates после cancellation consumer, а каждый новый экран удваивает callbacks. Как остановить?
asynccallbacksconcurrency - 78
Во время staged migration GCD-to-actor один path использует queue.sync, а другой await actor, что создаёт редкий deadlock. Как распутать hybrid design?
asyncdata-structuresconcurrency - 79
Cold launch регрессировал с 1,4 до 3,2 секунды после добавления трёх SDK. Как вернуть time to first frame?
- 80
First frame появляется за 1,2 секунды, но home screen нельзя использовать до завершения configuration request на 4,5 секунды. Как улучшить TTI?
config - 81
После release daily battery use вырос на 35%, а background traffic утроился у пользователей с включёнными notifications. Как локализовать проблему?
- 82
API p95 вырос с 400 мс до 1,8 секунды после выпуска retry logic, хотя server latency не изменился. Какое client behavior проверить?
resilienceapilatency - 83
App archive вырос на 86 МБ, а cold launch замедлился на 280 мс после добавления двух binary frameworks. Как решить, оставлять ли их?
- 84
On-device image classifier держит CPU около 85%, нагревает телефон и замедляется с 40 до 12 frames per second через три минуты. Как отреагировать?
zero-to-one - 85
Core Data sync создаёт 6 000 duplicate contacts после reconnect двух devices, хотя у каждого contact есть server ID. Как исправить model и data?
core-data - 86
Два devices offline редактируют одну SwiftData note, а reconnect молча теряет изменение title одного пользователя. Как задать conflict handling?
swift - 87
Core Data migration падает у 0,8% пользователей со stores, созданными четыре app versions назад. Что сделать до следующей попытки?
migrationscore-data - 88
Offline cart показывает 5 items, server принимает только 3 после reconnect, а badge продолжает показывать 5. Как reconcile state?
- 89
Combine settings screen иногда показывает старый profile после завершения двух save requests в обратном порядке. Как предотвратить rollback?
combinerollback - 90
Background Core Data save проходит успешно, но visible list остаётся stale до restart app в 7% sync sessions. Что проверить?
core-datasessions - 91
После установки iOS 18 UIKit navigation flow дважды закрывает sheet и попадает на неправильный screen в 4% sessions. Как локализовать OS regression?
uikitnavigationsessions - 92
Multi-window iPad app показывает alerts не в той scene, потому что legacy code использует UIApplication.shared windows. Как заменить deprecated assumption?
alerting - 93
App Store submission заблокирован, потому что обновлённому analytics SDK не хватает privacy-manifest declarations. Какова техническая реакция?
- 94
После обновления iOS пользователи с limited Photos access видят empty picker, хотя дали доступ к 12 images. Как отладить?
- 95
Переход на Swift 6 toolchain создаёт 1 300 concurrency errors, а быстрый patch добавляет @unchecked Sendable к 90 classes. Что вы сделаете?
concurrencyswift - 96
Self-sizing layout UICollectionView изменился после iOS update, из-за чего 8% message cells прыгают с 80 до 300 points. Как сдержать regression?
uikit - 97
Junior engineer исправляет checkout leak, добавляя weak self в 14 closures, но payment completion теперь пропадает в 3% медленных sessions. Как провести его через исправление?
closuresmentoringsessions - 98
Middle engineer отвечает на data race, помечая mutable cache как @unchecked Sendable, а Thread Sanitizer продолжает показывать failures. Как провести review?
soft-skillscachingvalidation - 99
Engineer пытается исправить scrolling 120 Гц, кешируя каждое transformed image, снижает hitches, но увеличивает память с 240 до 850 МБ. Как направить следующую итерацию?
cachingmemoryiteration - 100
Engineer исправляет force-unwrap crash, заменяя nil на empty string, но checkout начинает отправлять invalid addresses. Как превратить review в развитие judgment?