Это четвертая Лекция курса Stanford CS193p, весна 2021 года, и она сразу начинается с продолжения демонстрационного примера прошлой Лекции 3, на которой были сконструированы модель Model и ViewModel для карточной игры «на запоминание» Memorize. View (то есть UI) мы создали на Лекциях 1и 2. На этой Лекции архитектура MVVM реализуется во всей своей реактивной мощи.
После того, как MVVM заработает, профессор возвращается к слайдам, чтобы вкратце поговорить о двух вещах. Первая — это еще один системный ТИП Swift, называемый перечислением enum, а вторая — это специальная версия перечисления enum, называемая Optional. Наверное, это одно из самых важных перечислений enum, если не самое главное enum во всем Swift.
Реализация архитектуры MVVM.
На этой Лекции 4 мы научились делать такие модели Model, как эта модель игры Memorize:
Мы выяснили, что эти модели Model не зависят от UI. Вот почему мы импортируем только Foundation и почему в коде модели Model нет ссылок на что-либо в Views или ViewModel.
Наши модели Model имеют Данные (Data) наподобие наших карт cards и логику (Logic), которая в нашем случае представлена в виде функции choose (_ card: Card), выбора пользователем карты card и в который выполняет сопоставление карт на предмет СОВПАДЕНИЯ.
Мы также узнали, что модель Model — это единственный источник ИСТИНЫ. Вся информация о картах cards, лежат ли они “лицом” вверх, совпадают ли они и так далее, все это здесь, в модели Model. Больше нигде эта информация не хранится.
Мы уже знали из Лекции 1, что цель нашего View, который мы там создали, — отражать модель Model.
Напомним, что одно из определений переменной var body любого View— это «дай мне UI, который показывает текущее состояние модели Model«.
Мы узнали одну действительно замечательную вещь о наших Views, они — декларативны:
- ScrollView — вот он на UI.
- LazyVGrid — вот она на UI.
- Карты cards — вот они на UI.
По мере развертывания нашего кода, разворачивается и наш View. Всё, что мы декларируем в коде, появляется на UI.
То что мы видим на UI — полностью РЕАКТИВНО по отношению к тому, что происходит в нашей модели Model. И мы достигаем всего этого с помощью нашей ViewModel, которая привязывает View к модели Model.
Эта ViewModel может быть переводчиком (interpreter).
ViewModel также является «привратником» для модель Model по отношению к View. Она делает модель model private и раскрывает Views только ту информацию, которая им необходима.
ViewModel также делает возможным применение реактивной архитектуры в полном объеме потому, что замечает изменения в модели model благодаря тому, что Swift умеет обнаруживать изменения в структурах struct, а model — это структура struct MemoryGame. Swift не можете делать это в классах class, но он может обнаруживать изменения в структурах struct. Вот откуда наша ViewModel знает, когда что-то меняется в нашей модели model, и каждый раз, когда это происходит, публикует “Что-то изменилось…”. ViewModel способна это делать потому, что “ведет себя” как ObservableObject,
Достаточно просто маркировать ключевым словом @Published нашу переменную var model, и если в ней что-то изменится, будет вызвана скрытая переменная var objectWillChange со своим методом send(), и пусть Мир узнает, что что-то изменилось в нашей модели model.
Затем наш View, из-за того, что он пометил свою переменную var viewModel как @ObservedObject, он будет «слушать» эти изменения модели model и перестраивать свою переменную var body при любом изменении viewModel.model.
SwiftUI делает все это автоматически. И это происходит очень эффективно. Только те Views, которые действительно изменились, перестраивают свою переменную var body.
Итак, @ObservedObject меняется. Мы перестраиваем переменную var body, но когда до этого доходит, «прокрутка» ScrollView, «сетка» LazyVGrid и эти карты CardViews перестраиваются переменные свои var body в зависимости от того, действительно ли они изменились. Это один «контур» работы MVVM.
Другой «контур» работы MVVM связан с выполняем жест Tap или какого-то другого мультитач (multi touch) жеста и выражается в виде функции func в нашей ViewModel как НАМЕРЕНИЕ пользователя. В этом случае наша ViewModel выясняет, что нужно делать в модели Model.
Это в двух словах все о MVVM, в Лекции 4 все описывается очень подробно.
ТИП перечисление enum
Перечисления enum — это еще одна разновидность ТИПов наподобие структуры struct или класса class, все они создают блочные структуры данных, но в случае перечисления enum все его значения — дискретные состояния. Перечислению enum профессор уделяет очень много внимания.
ТИП Optional
Это самое ВАЖНОЕ перечислении enum во всем Swift, которое называется Optional. Optional — это причина великого ужаса для студентов, впервые изучающих Swift, но Optional — это просто перечисление enum, не более того.
Optional на удивление встречается так часто, что Swift представляет огромное количество хорошего “синтаксического сахара”, а по сути специального синтаксиса, для того, чтобы реально облегчить использование перечисления enum Optional. Восклицательный ! знак, вопросительный ? знак, двойной вопросительный ?? знак, nil, if let — все это “синтаксический сахар” для Optional, и профессор даёт прекрасную интерпретацию этому “синтаксическому сахару” с точки зрения обычных операций над перечислениями enum.
Код демонстрационного примера для Лекции 4 находится на Github для iOS 14 в папке Memorize L4.
Русскоязычный неавторизованный конспект Лекции 4, иллюстрированный, хронометрированный и представленный в виде PDF-файла, который можно скачать и использовать offline, а также в формате Google Doc доступны на платной основе.