1. Основы Swift и построение UI с UIKit и SwiftUI
Основы Swift и построение UI: UIKit против SwiftUI
Swift — это язык, который Apple создала с нуля в 2014 году, чтобы заменить Objective-C. Он безопасен по умолчанию: компилятор не позволит вам обратиться к nil-значению без явной проверки, что устраняет целый класс крашей ещё до запуска приложения. Но знать синтаксис — это только половина дела. Настоящее понимание iOS-разработки начинается с того, как Swift-код превращается в живой интерфейс на экране iPhone.
Типы данных и управление памятью: что происходит под капотом
Swift разделяет все типы на две категории: value types (типы-значения) и reference types (ссылочные типы). Это не просто академическое разграничение — от него зависит, как данные копируются и где живут в памяти.
struct, enum, Int, String, Array — value types. При присваивании создаётся копия.class — reference type. При присваивании передаётся ссылка на тот же объект.Почему это важно на практике? Представьте модель данных пользователя. Если вы используете class, то два разных экрана могут держать ссылку на один и тот же объект — изменение на одном экране неожиданно «сломает» другой. Именно поэтому в архитектуре MVVM модели данных принято делать struct.
Опциональные типы (Optional) — ещё один краеугольный камень Swift. String? означает «либо строка, либо ничего». Компилятор заставляет вас явно обработать оба случая:
Типичная ошибка новичка — использовать force unwrap (username!) везде, где компилятор «мешает». Это работает ровно до первого nil — и приложение падает с EXC_BAD_INSTRUCTION. Правило простое: ! допустим только тогда, когда вы на 100% уверены, что значение не может быть nil, и готовы объяснить почему.
Замыкания и функции высшего порядка
Замыкание (closure) — это блок кода, который можно передать как значение. В iOS они используются буквально везде: колбэки сетевых запросов, анимации, обработчики кнопок.
Важный нюанс — захват переменных (capture list). Замыкание «захватывает» переменные из окружающего контекста. Если замыкание живёт дольше объекта, который его создал, возникает retain cycle — утечка памяти:
Функции высшего порядка map, filter, reduce — это не синтаксический сахар, а инструмент для написания декларативного кода без побочных эффектов:
UIKit: императивный подход к интерфейсу
UIKit — это фреймворк, на котором построены все iOS-приложения с 2008 года. Он работает по императивной модели: вы явно говорите системе что делать и когда.
Центральная концепция UIKit — UIViewController. Это объект, который управляет одним «экраном» приложения. Его жизненный цикл критически важно понимать:
viewDidLoad — вызывается один раз при создании view. Здесь настраивают UI-элементы.viewWillAppear — вызывается каждый раз перед показом. Здесь обновляют данные.viewDidDisappear — здесь останавливают таймеры и отписываются от уведомлений.Типичная ошибка — делать сетевые запросы в viewDidLoad и не учитывать, что при возврате на экран данные не обновятся. Правильное место для обновления — viewWillAppear.
Пример создания кнопки и лейбла программно (без Storyboard):
Строка translatesAutoresizingMaskIntoConstraints = false — обязательна при использовании Auto Layout программно. Без неё система создаст конфликтующие констрейнты и интерфейс «сломается» на разных размерах экрана.
SwiftUI: декларативный подход
SwiftUI появился в 2019 году и перевернул подход к построению UI. Вместо «сделай это» вы описываете «как должно выглядеть»:
Ключевое понятие SwiftUI — @State. Это источник истины (source of truth) для локального состояния View. Когда @State-переменная меняется, SwiftUI автоматически перерисовывает только те части интерфейса, которые от неё зависят. Вам не нужно вручную вызывать reloadData() или setNeedsLayout().
Символ name, изменение автоматически отражается в родительском.
Управление состоянием в SwiftUI
| Обёртка | Когда использовать |
|---|---|
| @State | Локальное состояние одного View |
| @Binding | Передача состояния в дочерний View |
| @StateObject | Создание и владение ObservableObject |
| @ObservedObject | Наблюдение за ObservableObject, созданным снаружи |
| @EnvironmentObject | Глобальное состояние, доступное всему дереву View |
Типичная ошибка — использовать @ObservedObject там, где нужен @StateObject. Если View пересоздаётся (например, при обновлении родителя), @ObservedObject не сохранит объект — он будет создан заново. @StateObject гарантирует, что объект живёт столько, сколько живёт View.
UIKit vs SwiftUI: когда что выбирать
!Сравнение архитектур UIKit и SwiftUI: императивный и декларативный подходы к построению UI
> SwiftUI — это не замена UIKit, а другой уровень абстракции. Под капотом SwiftUI всё равно использует UIKit на iOS.
На практике в 2026 году большинство коммерческих проектов используют гибридный подход: новые экраны пишут на SwiftUI, а легаси-код остаётся на UIKit. Умение работать с обоими фреймворками — обязательное требование на большинстве iOS-вакансий.
| Критерий | UIKit | SwiftUI |
|---|---|---|
| Зрелость | С 2008 года, огромная экосистема | С 2019, активно развивается |
| Контроль над UI | Полный, пиксельный | Ограничен декларативной моделью |
| Сложные анимации | Гибко через UIView.animate | Проще через .animation() |
| Поддержка старых iOS | iOS 9+ | iOS 13+ (полноценно iOS 15+) |
| Скорость разработки | Медленнее | Быстрее для типовых экранов |
| Предпросмотр в Xcode | Нет | Canvas Preview в реальном времени |
Интеграция между фреймворками работает в обе стороны. UIKit-компонент можно встроить в SwiftUI через UIViewRepresentable, а SwiftUI-View в UIKit — через UIHostingController:
Навигация: как экраны связаны между собой
В UIKit навигацией управляет UINavigationController — стек экранов, где каждый новый экран «кладётся сверху»:
В SwiftUI навигация декларативна. В iOS 16+ рекомендуется использовать NavigationStack вместо устаревшего NavigationView:
Принципиальное отличие: в SwiftUI вы не говорите «перейди на этот экран» — вы говорите «когда значение типа Item появится в навигационном стеке, покажи DetailView». Это позволяет строить deep link-навигацию: просто добавьте нужное значение в стек, и приложение само «прыгнет» на нужный экран.
Понимание разницы между императивным UIKit и декларативным SwiftUI — это не просто знание двух API. Это два разных способа думать об интерфейсе. UIKit спрашивает: «Что нужно сделать прямо сейчас?» SwiftUI спрашивает: «Как должен выглядеть экран при данном состоянии?» Второй подход масштабируется лучше — именно поэтому Apple активно движется в его сторону, и именно поэтому архитектурные паттерны вроде MVVM так органично ложатся на SwiftUI.