Если вы хотите получить фундаментальные знания по разработке  iOS приложений с помощью SwiftUI, вам следует пройти стэнфордский курс CS193P. Предложенные в весеннем семестре 2023 года лекции Стэнфордского курса CS193P «Developing  Application for iOS with SwiftUI» («Разработка приложений для iOS с использованием SwiftUI») — это уже 3-я реинкарнация курса CS193P с фреймворком SwiftUI. На сайте курса вы найдете материалы, которые были предоставлены студентам Стэнфорда в течение весеннего семестра 2023 г.: ссылки на видео, слайды, домашние задания и код демонстрационных примеров для iOS 16 и Xcode 14

На данный момент конспекты этого курса на русском языке находятся в открытом доступе:

1-ая часть (Лекции 1-5)

2-ая часть (Лекции 6-10)

3-ая часть (Лекции 11-15)

В настоящий момент действуют Xcode 15 / iOS 17, которые были представлены на WWDC 2023 уже после завершения курса CS193P, наиболее значимое обновление внесено в механизм реактивного UI в SwiftUI (макрос @Observable против протокола ObservableObject). Тем не менее, ObservableObject присутствует в Xcode 15 / iOS 17, и может использоваться совместно с новым макросом @Observable.

В иллюстрированных  русскоязычных конспектах этого курса сделаны пометки, касающиеся изменений в iOS 17, а также восполнены некоторые фрагменты Лекций, где есть звук, но пропадает изображение, когда профессор демонстрирует что-то «в живую». Для большинства Лекций представлена версия с  использование макроса @Observable вместо протокола ObservableObject, в ряде случаев это потребовало нетривиальных решений. 

Профессор придерживается “повествовательного” (Narrative) способа обучения работе с такой системой, как SwiftUI. Этот способ заключается в том, что вы изучаете всех “персонажей” и настройки SwiftUI, попутно следуя какому-то сюжету, и строите новый мир, постепенно добавляю в него все новые и новые кусочки кода. И не просто добавляются какие-то несвязанные фрагменты кода, a появление любой строчки кода четко объясняется сюжетом разрабатываемого приложения. В результате перед вами предстает полная картина разработки iOS приложений. Именно так профессор рассказывает историю разработки приложения на SwiftUI.

Традиционно в этом курсе представлена разработка всего двух приложений. Первое — это карточная игра “на совпадение” Memorize для iPhone (Лекции 1-9), a второе  — приложение Emoji Art для создания “картин” из эмодзи (смайликов) и фоновых изображений, скачиваемых из Интернета, для iPad и Mac (Лекции 10-15). 

Игра  Memorize имеет довольно простую логику и один экран, на котором всё и происходит: сама игра и подсчет очков. В ней нет ни навигации, ни сложных жестов, ни всплывающих окон, ни многопоточности. Но она призвана отточить ваши основные навыки программирования в Swift и проектирования Reactive UI в SwiftUI - система ТИПов Swift, протоколы protocol, Generics, расширения extension, Optional, архитектуру MVVM + MVI, @ViewBuilder, Layout, ViewModifier, неявная (implicit) и явная (explicit) анимации, переходы Transition, TimelineView, matchedGeometryEffect.

Второе приложение Emoji Art - более сложное приложение для создания произведений искусства в виде картин из эмодзи и фоновых изображений, выбираемых из интернета и размещаемых с помощью механизма Drag & Drop. Здесь уже две MVVM: одна - для самой картины, a другая - для хранилища палитр, которое можно редактировать, причем вторая модель Model для палитр предоставляется вашему View напрямую, но при этом ViewModel остаётся, и Пол Хэгерти объясняет почему. В этом приложении уже  есть и новая навигация, и новая многопоточность с использованием actor, сочетание жестов Pan и Pinch с @GestureState, a также использование файловой системы iOS и UserDefaults для постоянного хранения и т.д. Финальная версия этого приложения вообще является документо-ориентированным приложением.

Хотя структура курса CS193P Spring 2023 во многом аналогична версии CS193P Spring 2021, содержание сильно отличается, поскольку SwiftUI существенно усовершенствовался за эти 2 года: изобретены новые “комбинирующие” View (LazyVGrid, LazyHGrid), которые вдохновили на создание собственного AspectVGrid, расширились возможностей Shape, появились новые View модификаторы (.onChange) и "Обертки” Свойств (@FocusState), новые виды анимации (TimelineView, matchedGeometryEffect), существенно упростилось выполнение Drag & Drop за счет нового протокола Transferable,  изменилась концепция навигации (NavigationStack / SplitView, NavigationLink, .navigationDestination), появилась абсолютно новая концепция многопоточности. Профессор даже использует более современный вариант многозадачности на iPad - Stage Manager.

Каждая тема прорабатывается троекратно: сначала профессор рассказывает проблему на слайдах, потом показывает в демонстрационном примере и, наконец, вы закрепляете ее, выполняя Домашнее Задание, которых в курсе 6. 

Кроме того в курсе есть так называемые “Задания на чтение”, их 3, которые, по сути, являются руководством к тому, как рационально изучить язык программирования Swift за короткое время.

Слушать Лекции лучше всего, параллельно программируя в Xcode. Именно в этом состоит Домашнее Задание # 1, и тут вам реально может пригодиться русскоязычный иллюстрированный  конспект, ибо не нужно перематывать Video туда-сюда, и весь материал у вас под рукой.

Вот краткое содержание Лекций курса «Developing  Application for iOS with SwiftUI Spring 2023»

Лекция 1. Начало работы со SwiftUI.

Введение в курс. Основы SwiftUI. Начинаем работать над первым приложением этого семестра — карточной игрой под названием Memorize. Это будет основой учебного материала для первых нескольких недель курса. Демонстрация основ композиции элементов пользовательского интерфейса (UI), используемой в SwiftUI, происходит в среде разработки Xcode.
Смотреть в YouTube.
Русскоязычный иллюстрированный конспект Лекции 1.
Задание на чтение 1.

Лекция 2. Больше о SwiftUI.

Разработка игры Memorize продолжается. Создание пользовательских View. Обработка жеста касания TapGesture. Добавление кнопок Button. Факторизация повторяющегося кода.

Смотреть в YouTube.
Русскоязычный иллюстрированный конспект Лекции 2.
Задание на программирование 1.

Лекция 3. MVVM.

Концептуальный обзор архитектурной парадигмы, лежащей в основе разработки iOS приложений с использованием SwiftUI, известной как MVVM. Объяснение фундаментального компонента понимания языка программирования Swift: его системы ТИПов. Начинаем применять это для игры Memorize.

Смотреть в YouTube.
Русскоязычный иллюстрированный конспект Лекции 3.

Лекция 4. Применение MVVM.

Применяем архитектуру MVVM к приложению Memorize. Попутно познакомимся с дженериками (Generics) и получим представление о static переменных и функциях. Создание реактивного UI. Продолжим изучать возможности Xcode.

Смотреть в YouTube.
Русскоязычный иллюстрированный конспект Лекции 4.
Задание на чтение 2

Лекция 5. Протоколы protocol, перечисления enum, Optional

Основная тема — протоколы (Identifiable, Equatable и т. д.). Кроме того, рассматривается ещё один важный элемент системы ТИПов в Swift  — перечисление enum. Много внимания уделено самому важному перечислению enum в Swift  —  Optional. Логика Memorize завершается использованием вычисляемых свойств.

Смотреть в YouTube.
Русскоязычный иллюстрированный конспект Лекции 5.
Задание на программирование 2.

Лекция 6. Расположение на экране Layout, @ViewBuilder

Как SwiftUI отображает свои Views, учитывая доступное ему пространство? И как мы можем создать свои собственные «механизма компоновки» Views? Обновление игры Memorize, чтобы максимально эффективно размещать любое количество карт на экране без прокрутки. «Закулисье» @ViewBuilder, используем @ViewBuilder для вычисляемых переменных, в инициализаторах init для аргументов-функций и переменных var в структурах struct

Смотреть в YouTube.
Русскоязычный иллюстрированный конспект Лекции 6.
Задание на чтение 3
Задание на программирование 3.
Код AspectVGrid.swift.

Лекция 7. Геометрические фигуры Shape, модификаторы ViewModifier, константы Constants

Как рисовать геометрические фигуры Shape в SwiftUI (например, геометрическую фигуру в виде «пирога» Pie, необходимую для будущей анимационной «фичи» игры Memorize). Как создавать собственные модификаторы ViewModifier (например, тот, который «картифицирует» (то есть превращает в карту) любое View, а не только нашу игровую карту  Memorize). Попутно представим формализм для аккуратного добавления констант в наш код.

Смотреть в YouTube.
Русскоязычный иллюстрированный конспект Лекции 7.
Код Cardify.swift.
Код Pie.swift.

Лекция 8. Анимация (часть 1)

Первая часть анимационного приключения, состоящего из двух частей. Неявная (implicit) анимация против явной (explicit) анимации. Кривые анимации. Анимация модификатора ViewModifier (переворот карт).

Смотреть в YouTube.
Русскоязычный иллюстрированный конспект Лекции 8.
Задание на чтение 4.

Лекция 9. Анимация (часть 2)

Запуск анимации при появлении Views (усовершенствование «летящего» счета score). Анимация изменений состояния с помощью TimelineView ( «бонусные очков» для «пирога» Pie). Анимация  View «переходов» Transition на экран и с экрана и сдача карт в игре Memorize с помощью модификатора matchedGeometryEffect.

Смотреть в YouTube.
Русскоязычный иллюстрированный конспект Лекции 9.
Задание на программирование 4.
Код Memorize.

Лекция 10. EmojiArt

Создание приложения для iPad с нуля: Emoji Art. Это возможность заново взглянуть на MVVM, поскольку это приложение имеет совершенно другую архитектуру, чем игра Memorize. Оно использует SwiftUI Drag & Drop механизм для установки фонового изображения документа Emoji Art и добавления эмодзи (смайликов) в произведения искусства, которые вы можете создать с помощью этого приложения.

Смотреть в YouTube.
Русскоязычный иллюстрированный конспект Лекции 10.
Код EmojiArt L10.

Лекция 11. Жесты, вторая MVVM

Обработка мультитач-жестов (масштабирование и перемещение по экрану документов Emoji Art). Начинаем создавать более сложные приложения, добавив в приложение вторую конструкцию MVVM (палитры смайликов Emoji Art).

Смотреть в YouTube.
Русскоязычный иллюстрированный конспект Лекции 11.
Задание на программирование 5.
Код EmojiArt L11.

Лекция 12. Постоянное хранение (Persistence). Обертки свойства (Property Wrappers)

Обеспечение сохранения информации между запусками приложения. Emoji Art сохраняет свой документ, а также любые изменения, внесенные в его палитры. Файловая система и UserDefaults. Узнаем больше о том, как работают оболочки свойств (например, @State, @Published и т. д.).

Смотреть в YouTube.
Русскоязычный иллюстрированный конспект Лекции 12.
Код EmojiArt L12.

Лекция 13. Представляющие (Presenting) Views, Navigation

До сих пор каждое из наших двух приложений состояло только из одного основного «СontentView» ( EmojiMemoryGameView игры Memorize или EmojiArtDocumentView для приложения Emoji Art). Более сложные приложения должны представлять множество различных видов Views. Добавление в Emoji Art механизмов редактирования его палитр, представление всплывающих модальных окон .popover и .sheet, а также навигация между Views.

Смотреть в YouTube.
Русскоязычный иллюстрированный конспект Лекции 13.
Задание на программирование 6.
Код EmojiArt L13.

Лекция 14. Многопоточность, Обработка ошибок

UI мобильных приложений должен всегда быть отзывчивым, даже если он должен выполнять действия, которые занимают (относительно) много времени (например, загрузка чего-либо из Интернета). Язык Swift имеет встроенный механизм, позволяющий прояснить, какие действия должны происходить «в фоновом режиме», чтобы не замедлять работу UI. При этом также важна обработка непредвиденных ошибок, поэтому в этой лекции обе темы представлены вместе.

Смотреть в YouTube.
Русскоязычный иллюстрированный конспект Лекции 14.
Код EmojiArt L14.

Лекция 15. Документо—ориентированная архитектура

Emoji Art, конечно, хочет поддерживать наличие нескольких документов (как рядом на iPad, так и в нескольких окнах на Mac). SwiftUI имеет мощный встроенный пользовательский интерфейс для решения этой проблемы, и попутно мы получим поддержку Undo/Redo в Emoji Art!

Смотреть в YouTube.
Русскоязычный иллюстрированный конспект Лекции 15.
Код EmojiArt L15.


Пол Хэгерти очень понятно объясняет ключевую концепцию SwiftUI - единственный “источник истины” (Single Source Of Truth) через систему обратных “привязок” Binding из View через ViewModel к Model и внедрения ViewModel в иерархию Views через @EnvironmentObject. Это позволяет вам напрямую редактировать данные, хранящиеся в другом месте, из View любого уровня иерархии и избежать дублирования хранения данных в разных местах. 

Но всё это возможно благодаря механизму реактивного UI в SwiftUI, основу которого составляет протокол ObservableObject.  Правда дважды при разработке приложения Emoji Art  Пол Хэгерти выходит на границы возможностей ObservableObject: при использовании Userdefaults как вычисляемого свойства с get {} и set {} для хранения палитр palettes заставляет отказаться от явного применения @Published и при использовании массива [ObservableObject], который автоматически не является ObservableObject.

Однако начиная с iOS 17, iPadOS 17, macOS 14, tvOS 17 и watchOS 10, уже после завершения курса CS193P, SwiftUI предлагает новый фреймворк Observation, реализующий паттерн наблюдателя, и макрос @Observable против протокола ObservableObject.

Использование Observation обеспечивает вашему приложению следующие преимущества:

  • Отслеживание Optional значений и коллекций Collection объектов, что невозможно при использовании ObservableObject.

  • Использование существующих примитивов потока данных, таких как @State и @Environment, вместо основанных на объектах эквивалентов, таких как @StateObject и @EnvironmentObject.

  • Обновление Views на основе изменений наблюдаемых свойств, которые считывает body конкретных View, а не любых изменений свойств, происходящих с наблюдаемым объектом, что может повысить производительность вашего приложения.

Поэтому все объяснения Пола Хэгерти относительно  единственного “источника истины” (source of truth) остаются верными с заменой  протокола ObservableObject на макрос @Observable, @StateObject на@State, @EnvironmentObject на @Environment, @ObservableObject вообще убрать или заменить на@Bindable, все это изложено в “Правилах Миграции от протокола ObservableObject  к макросу @Observable”. В русскоязычном конспекте сделаны все необходимые пометки на полях и для всех демонстрационных примеров в GitHub представлена версия с пометкой “Observation”.

Кроме того, наибольшее впечатление производит простое объяснение и реализация многопоточности (async, await, Task) при пользовательской загрузке изображения из Интернета на основе такой абстракции, как конечный автомат, с параллельной обработкой ошибок (throws, try, do {} catch {}).

Отдельного упоминания требует способ хранения DocumentGroup данных, воспринимаемых пользователями как «документы», а именно таким и является наше приложение Emoji Art. DocumentGroup способна превратить Emoji Art в многодокументное приложение, которое работает как “родное” приложение в среде Files как на iOS, так и на Mac. Надо сказать, что в интернете не так много информации  о полноценном применении DocumentGroup, так что это просто подарок тем, кто создает приложения, основанные на «документах».

Ссылки:

  1. Оригинальный сайт стэнфордского курса CS193P «Разработка  iOS приложения с помощью SwiftUI» семестр Весна 2023 (английский)

  2. Русскоязычный конспект курса CS193P Весна 2023 (русский)

  3. “Правилах Миграции от протокола ObservableObject  к макросу @Observable”.

  4. Stalk Your Data in SwiftUI 5 with Observable

  5. Nested Observables in SwiftUI.

  6. Comparing @Observable to ObservableObjects

  7. SwiftUI Observable in iOS 17.