# Лекция Stanford: «Списки, навигация и Observable-модели в SwiftUI»

Источник: https://www.youtube.com/watch?v=NnJ91M9PRYo
Канал: Stanford Online
Опубликовано: 03.12.2025

---

## Создание сложных интерфейсов: iOS-разработка на SwiftUI
[[JUMP:00:05]]

Лекция №10 курса Stanford CS193p (весна 2025 года) полностью посвящена практической разработке интерфейсов на SwiftUI. Лектор демонстрирует эволюцию приложения для игры в Mastermind, переходя от простых списков к сложной навигации, работе с данными как классами и кастомизации UI-элементов.

### 🧩 Идентификация и протоколы Hashable/Identifiable
[[JUMP:00:35]]

Для корректной работы `ForEach` в SwiftUI каждый элемент коллекции должен быть уникальным, стабильным и соответствовать протоколу `Hashable`.

*   **Проблема уникальности:** При использовании `ForEach` с элементами данных необходимо задать идентификатор. Использование `id: \.self` требует, чтобы тип данных был `Hashable`.
*   **Синтез Hashable:** Swift может автоматически синтезировать `Hashable` для структур, если все их поля также являются `Hashable`. Если `Kind` (enum) или другие свойства не соответствуют этому требованию, их нужно обновить вручную.
*   **Использование pegs:** Лектор отмечает, что использование `pegs` (колышков) в качестве уникального идентификатора часто является более семантически верным и простым решением, чем перегрузка структуры протоколами.
*   **Identifiable:** Если модель реализует протокол `Identifiable`, можно опустить явное указание `id:`, так как SwiftUI будет использовать свойство `id` автоматически. Однако лектор предостерегает от чрезмерного использования `Identifiable` для простых структур, если их идентификация зависит от контекста (например, поиск по цвету).

### 📜 Архитектура списков (List)
[[JUMP:14:34]]

Компонент `List` является базовым инструментом для создания сложных интерфейсов в iOS, объединяя функциональность `VStack`, `ScrollView` и `ForEach`.

*   **Динамические списки:** `List` может динамически отображать коллекции данных, предоставляя гибкие возможности для кастомизации каждой строки.
*   **Морфология:** Для работы с множественным числом (например, "1 попытка" против "2 попыток") в SwiftUI встроен механизм морфологии, который корректно склоняет слова в зависимости от языка, избегая примитивных тернарных операторов.
*   **Кастомизация:** С помощью модификаторов (например, `.listRowSeparator`, `.listBackground`) можно менять внешний вид строк, скрывать разделители и добавлять фон.
*   **Секции:** `List` поддерживает разбиение на логические разделы (`Section`), что полезно для группировки настроек или различных типов данных.

### 🗺 Навигация: Stack и Destination
[[JUMP:32:55]]

Для перехода между экранами SwiftUI использует систему навигации, управляемую `NavigationStack`.

*   **NavigationStack:** Создает среду, в которой работают `NavigationLink`. Этот компонент автоматически управляет кнопкой «Назад» и заголовками.
*   **Передача данных:** Для обмена данными между списком и детальным представлением используется `@Binding`. Это позволяет изменениям в игре мгновенно отражаться в списке.
*   **Toolbar:** Модификатор `.toolbar` позволяет добавлять кнопки (например, `EditButton` для удаления/сортировки строк) в панель навигации. Использование семантических позиций (например, `.primaryAction`) вместо жесткого задания сторон позволяет SwiftUI лучше адаптировать интерфейс под разные устройства.

### 🏛 Модели данных: Struct vs Class
[[JUMP:51:33]]

Лектор сравнивает подход работы с данными через структуры (передача по значению/Binding) и классы (передача по ссылке).

*   **@Observable:** При использовании классов в качестве модели данных необходимо помечать их как `@Observable`. Это позволяет SwiftUI «видеть» изменения, происходящие внутри объекта в куче (heap).
*   **Эффективная навигация:** Для больших списков использование `.navigationDestination(for:...)` предпочтительнее, чем создание `NavigationLink` напрямую с представлением, так как это предотвращает ненужное создание объектов, которые пока не отображаются на экране.
*   **Hashable для навигации:** Чтобы использовать типизированную навигацию с `navigationDestination`, модель данных должна соответствовать протоколам `Identifiable` и `Hashable`.