Лекция 3. MVVM. CS193P Spring 2023.

Ниже представлен начальный фрагмент Лекции 3 Стэнфордского курса CS193P Весна 2023 «Разработка iOS приложений с помощью SwiftUI«.
Полный русскоязычный неавторизованный конспект Лекции 3 в формате Google Doc и в виде PDF-файла, который можно скачать и использовать offline, доступны на платной основе.
Код находится на GitHub.

С полным перечнем Лекций и Домашних Заданий на русском языке можно познакомиться здесь.

В этой Лекции вы увидите, наверное, самое большое количество слайдов на протяжении всего семестра, но нам нужно изучить базовую архитектуру прежде, чем погрузиться в следующую часть демонстрационного приложения, которая будет освещаться во второй половине сегодняшней Лекции.
Есть вопросы, прежде чем я начну? Хорошо, нет.
Итак, Лекция номер 3.
У нас есть две очень большие темы для разговора: одна из них — MVVM, которая представляет собой архитектуру, парадигму дизайна, которую вы будете использовать для создания iOS приложений, вторая —  система ТИПов Swift:

Сегодня

MVVM

  • Парадигма конструирования

Система ТИПов Swift

  • structструктура
  • class — класс
  • protocol — протокол
  • “Don’t Care” ТИП (Generic) — “Не важно какой” ТИП (Дженерик)
  • enum — перечисления
  • functions — функции

Возвращаемся к Демо!

  • Применение MVVM к Memorize

В Swift есть разные ТИПы:  структура struct, протокол protocol и многое другое.
Итак, это две основные темы Лекции 3, а затем я вернусь к демонстрационному приложению, в которой мы начнем создавать логику игру Memorize, то есть что происходит, когда вы кликаете на карты.

Архитектура MVVM

Итак, что это за штука MVVM?
Надо сказать, что в Swift очень важно отделить логику и данные вашего приложения от пользовательского интерфейса (UI).
Это действительно очень важно.В некотором смысле, SwiftUI построен на той идее, что у вас будут ДАHHЫЕ и ЛОГИКА, которые связаны с тем, что делает ваше приложение, и еще у вас будет UI, который покажет это пользователю и будет взаимодействовать с пользователем как совершенно отдельная вещь. Так что это реально очень важно.
Та часть приложения, которая связана с ДАННЫМИ и ЛОГИКОЙ, например, в  нашем приложении Memorize это “что происходит, когда вы кликаете на карте?” или “карты лежат лицом вверх или лицом вниз?”, все это, мы называем Model (Моделью) нашего приложения. Вы услышите, что я использую это слово Model (Модель) сотни раз. Вся логика и данные “живут” в Model (Модели).

Всё, что мы делали до сих пор на этом курсе, был только UI и иногда мы будем называть его View, потому что это наш «взгляд», наш портал на Model (Модель).

Model и UI

Отделение «Логика и данных» от UI

  • SwiftUI очень серьезно относится к отделению логики и данных приложения от UI
  • Мы называем логику и данные нашей Model (Моделью)
  • Это может быть структура struct или SQL база данных или некоторый код машинного    обучения или многие другие вещи
  • Или любая комбинация таких вещей
  • UI — это “параметризованная” оболочка, которую “питает” и вызывает к “жизни” Model
  • Думайте о UI как о “визуальном” проявлении Model (Модели)
  • Model (Модель)  — это где “живут” такие вещи как isFaceUp и cardCount (a не @State в UI)
  • SwiftUI заботится о том, чтобы UI перестраивался всякий раз, когда Model (Модель) изменяется

Model (Модель) может быть одной структурой struct. Это может быть целая SQL база данных, полная всяких сущностей. Возможно, что это может быть какой-то код машинного обучения.
Это может быть  похоже на REST API для Интернета. Это может быть почти что угодно.
Наша Model (Модель) — концептуальная вещь, это не просто одна структура struct, хотя в нашем приложении Memorize это будет действительно одна структура struct, так как у нас очень простое маленькое стартовое приложение. Но я не хочу, чтобы вы думали, что ваша Model (Модель) не может быть более мощной и сложной.

Что касается UI части нашего приложения, то это на самом деле просто “параметризованная” оболочка, которую Model “кормит”. Одна из лучших фраз, которые я слышал о UI — это визуальное проявление Model, потому что Model — это то, чем реально является ваше приложение, это игра на запоминание Memorize, вот что это такое, так что вся эта логика игры находится в Model.
UI — это просто то, как вы показываете Model пользователю, то есть её визуальное проявление. Вам действительно хочется думать об этом именно так.
То, что мы разместили наши переменные isFaceUp и cardCount в @State, принадлежат Model. Всё это касается игры, в которую мы играем. Поэтому мы не хотим, чтобы они были в UI, и я постараюсь избавиться от них в UI, поместив их в нашу Model.

Одна из очень важных вещей, которые делает Swift, супер важная его обязанность, заключается в том, чтобы обеспечить отражение в UI любых изменений в Model. Model отображается в UI. И для этого у Swift есть огромная инфраструктура для этого. 
В свою очередь ВАМ НЕ нужно нести ответственность за то, что все, что есть в вашей Model, отображалось бы в UI. Swift всё это сделает за вас. Вам же просто нужно дать Swift несколько подсказок о том, что в Model влияет на ваш UI. Как только вы сделаете это единожды, дальше волноваться об этом не придется. 
Беспокоиться следует о том, чтобы разделить эти вещи: Model и UI.
Но если мы разделим Model и UI, как они будут между собой взаимодействовать? Потому что очевидно, что им нужно поговорить друг с другом.

Я свел это к трем различным способам коммуникации Model и UI. Возможно, существуют и другие способы, но большинство вещей уместилось бы в одной из этих трех категорий. 

Model и UI

Подключение Model к UI

Существует несколько вариантов подключения Model к UI …

  1. Редко, но Model может быть просто @State в View (это минимум разделения, его практически нет)
  2. Model может быть доступна только через “привратника” (gatekeeper) — класс classView Model” (полное разделение)
  3. Существует “View Model” класс class, но Model все еще доступна View напрямую (частичное разделение)

Почти всегда этот выбор зависит от сложности Model. . .

  • Model представляет собой SQL + struct(s) + что-то еще — скорее всего опция #2
  • Model представляет собой простейший кусок данных и не имеющая практически никакой логики — скорее всего опция #1
  • Что-то между опцией 1 и опцией 2 — опция #3
  • Сегодня мы будем говорить об опции #2 (полное отделение).
  • Мы называем такую архитектуру, которая подключает Model к UI таким образом, MVVM.
  • Model — View — ViewModel
  • Это основная архитектура для любого разумного по сложности SwiftUI приложения
  • Мы быстро взглянем на то, как использовать  #3 (частичное разделение) путем минимальных изменений MVVM.
  1. Редко, но один из способов, каким можно подключить Model к UI, заключается в том, что Model (Моделью) является @State в View. Я имею в виду, что если вы всю Model, всю логику в вашем приложении разместите в @State в вашем View, то, очевидно, View может получить к ней доступ. Это крайне минимальное разделение. Я бы, наверное, не стал этого делать.
  2. Давайте поговорим о том, что мы будем делать в ближайшее время. Номер 2 заключается в том, что Model доступна для UI только через “привратника” (Gatekeeper). У нас будет привратник (Gatekeeper), class ViewModel, и работа этого “парня” — поддерживать безопасную коммуникацию UI и Model. Это основной способ, который мы будем использовать в наших приложениях, и этот способ называется MVVM. Номер 2 мы будем использовать в 99% случаев при создании приложений
  3. Номер 3 является своего рода гибридом первых двух, то есть у нас есть этот привратник (gatekeeper), который мы называем ViewModel, но иногда у нас есть прямой доступ к Model. У нас будет public переменная var в Model, которая доступна UI и через неё UI на самом деле разговаривает с Model напрямую, прямо с игрой Memorize. По сути, это гибрид первых двух.

Итак, как узнать, какой из этих вариантов использовать? 

Читать далее

Лекция 2. Ещё больше SwiftUI. CS193P Spring 2023.

Ниже представлен начальный фрагмент Лекции 2 Стэнфордского курса CS193P Весна 2023 «Разработка iOS приложений с помощью SwiftUI«.
Целиком конспект Лекции 2 можно прочитать на Google Doc здесь.
Код находится на GitHub.

С полным перечнем Лекций и Домашних Заданий на русском языке можно познакомиться здесь.

Иногда мне нравится начинать свои Лекции с возврата на предыдущую лекцию и доделывать всё, что забыл там сделать. Вы видели, как проходят Лекции —  мне нужно слишком многое вам рассказать. и иногда я слишком быстро что-то проскакиваю.

Режим Выбора (Selection)  в Preview


Итак, я хотел бы начать с возвращения к предыдущей Лекции и немного уточнить одну вещь, связанную с инспектором.
 

Помните, я говорил вам, что вы можете войти в режим Выбора (Selection) внизу вашего PreView.
В режиме Выбора (Selection) вы сможете выбирать элементы вашего UI или даже несколько элементов одновременно.

Пару замечаний об этом. Я говорил о том, почему это важно, ведь если вы умеете программировать, зачем вам это нужно? И я приводил примеры,  кому это нужно: локализаторам или дизайнерам вашего UI, которые могут и не быть программистами. 
Однако не значит, что это не имеет абсолютно никакой важности лично для вас. Это может быть хорошо для настройки определенных элементов UI.

И еще одна вещь, которую следует отметить по этому поводу. Я не думаю, что я упомянул о том, что этот режим Выбора (Selection) работает в обе стороны. Если я кликну на  строка кода, то будет выбраны (голубой рамкой) элементы UI, представляющие этот код:

И наоборот, если вы выберите элемент UI, то будет подсвечен код, представляющий этот элемент UI. Другими словами, дело не только в том, что ВЫ выбираете, а что выбирает XCode. Если вы выберете любой из двух вариантов, то будет выбран другой, поэтому я хочу, чтобы вы это поняли. 
И тогда как программисту, почему бы вам не повозиться с цвет или с некоторыми отступами или с чем-то еще в этом роде без необходимости постоянно печатать и редактировать исходный код. Это зависит от того, что вам нравится. Лично я люблю редактировать исходный код. Это как бы вытекает из моего мироощущения, поэтому мне нравится все делать в коде. Но некоторым людям нравится кликать на кнопки. И поэтому я просто не хотел принижать возможности Инспектора и режима Выбора (Selection). Это может быть интересным и значимым.
Итак, это было единственное, к чему из прошлой Лекции я хотел вернуться .

Настройки проекта  Project Settings 

Еще одна вещь, которую я хотел бы упомянуть.  Когда мы вышли на Навигатор в раздел Файлы, я сказал: “Посмотрите, есть три файла: MemorizeApp, ContentView и Assets. Но на самом деле есть еще одна вещь,  вы можете кликнуть на самой верхней строке иерархии, это что-то вроде файла, и увидеть настройки Project Settings вашего проекта. 

Читать далее

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

Ниже представлен начальный фрагмент Лекции 1 Стэнфордского курса CS193P Весна 2023 «Разработка iOS приложений с помощью SwiftUI«. Целиком конспект Лекции 1 можно прочитать на Google Doc здесь. Код находится на GitHub.

С полным перечнем Лекций и Домашних Заданий на русском языке можно познакомиться здесь.

Введение

Привет, Интернет, и добро пожаловать на курс CS193P Стэнфордского университета Весна 2023: Разработка приложений для iOS с использованием SwiftUI.

Я —  Пол Хегарти. Я веду этот курс уже 13 или 14 лет, и время от времени я записываю его и выкладываю в Интернет на всеобщее обозрение, чтобы вы могли видеть, чем мы занимаемся здесь, в Стэнфорде.

К сожалению, в этом семестре я этого не сделал. Мы вернулись в кампус после пандемии и я не установил все необходимые камеры для этого, так что прошу прощение за это. Тем не менее, я записал скриншоты экрана своего ноутбука. Мне пришлось это сделать, потому что моим студентам при выполнении Домашних Заданий 1 и 2 необходимо следить за тем, что я делаю, иногда им нужно иметь возможность вернуться назад и увидеть код демо-версии. Это хорошо и для вас, потому что вы можете делать то же самое. Это также очень хорошо для моих основных слайдов, где я рассматриваю некоторые концепции SwiftUI и т. д. А еще я весь семестр держал в ухе этот AirPod, так что, надеюсь, звук во всем этом будет довольно хорошим.

Однако есть вещи, которые вы не увидите на экране. Например, для карточной игры, которую мы разрабатываем на этом курсе, я сделал несколько настоящих карточек. 

Я также довольно часто использую LEGO (Лего) в качестве аналогии SwiftUI. Вы не сможете увидеть мой вертолет LEGO и мою печально известную сумку LEGO … 

… но обязательно услышите о них, когда будете слушать демонстрационные примеры.

А еще у нас есть совершенно замечательный большой проекционный экран, и я обычно ходил перед ним и жестикулировал при написании кода. Очевидно, вы не увидите на видео моих жестов. Надеюсь, что шрифты будут достаточно большими, чтобы вы могли их увидеть на небольшом устройстве, но если нет, то вам, возможно, придется перейти на iPad или что-то в этом духе. Но я думаю, что в целом все будет очень хорошо.

Итак, это университетский курс. Лекции курса CS193P Spring 2023 читаются каждую неделю в течение 10 недель. Мы пытаемся понять не только то, как разработать приложение для iOS, но и то, как работает система SwiftUI в целом?

Читать далее

WWDC 2023. Новый фреймворк SwiftData для управления данными. Эксперименты

SwiftData дебютировал на WWDC 2023 в качестве замены фреймворка Core Data и обеспечивает постоянное хранение данных на Apple устройствах и беспрепятственную синхронизацию с облаком iCloud. Весь API SwiftData построен вокруг современного Swift.

Примечание. SwiftData является частью iOS 17, и на момент написания этой статьи мы имеем версии Xcode 15.0 и iOS 17.0 .

В SwiftData, в отличие от своего предшественника, базы данных Core Data, очень просто создать Схему (или Модель Данных) для постоянного хранения информации в вашем приложении. Для этого прямо в коде создаются обычные Swift классы class со свойствами, имеющими обычные базовые Swift ТИПы, ТИПы или другие Swift классы Схемы. Вы также можете использовать как Optional, так и НЕ-Optional ТИПы.

Чтобы превратить эти обычные Swift классы в постоянно хранимые объекты, Apple дала нам «волшебную палочку» в виде макросов, самым главным из которых является макрос @Model.

Если вы пометите макросом @Model обычные Swift классы, то получите не только постоянно хранимые объекты, но и сделаете их Observable, Hashable и Identifiable, и вам не нужно предпринимать никаких дополнительных усилий при использовали их в SwiftUI, ибо новый в iOS 17 протокол Observable обеспечит вам «живое» отображение на UI всех изменений ваших хранимых объектов, а Identifiable и Hashable позволят беспрепятственное использовать их в списках ForEach.

В SwiftData, в отличие от Core Data, нет никаких внешних файлов для Модели Данных и никакой «закулисной» генерации старых Objective-C классов, которые еще нужно адаптировать для использования в Swift. В SwiftData всё исключительно просто.

Кроме того, в SwiftData существенно, по сравнению с Core Data, упрощена выборка данных и отображение её результатов на UI. Для этого предназначена «обертка свойства» @Query, для которой вы можете указать предикат Predicate (то есть условия выборки данных) и сортировку результата SoreDescriptor. Новый мощный предикат Predicate выгодно отличается от старого предиката NSPredicate Core Data тем, что теперь вы можете задавать условия выборки данных, используя операции самого языка программирования Swift, а не какую-то замысловатую форматированную строку.

SwiftData дополнен такими современными возможностями как Swift многопоточность и макросы. В результате в Swift 5.9 мы получили, по определению самого Apple, “бесшовное” взаимодействие с постоянным хранилищем данных в нашем приложении. SwiftData совершенно естественным образом интегрируется в SwiftUI и прекрасно работает с CloudKit и Widgets.

Если вы начнете работать со SwiftData, то вообще не почувствуете даже «духа» Core Data, всё очень Swifty. Apple настаивает на том, что SwiftData — это совершенно отдельный от Core Data фреймворк, нам точно неизвестно, является ли SwiftData «оболочкой» Core Data, но даже если это так, то она настолько элегантно, интуитивно и мастерски реализована, что у вас будет ощущение работы исключительно в «родной» cреде языка программирования Swift.

В этом посте я покажу вам, как:

  • определить Схему данных в SwiftData, 
  • выполнить CRUD операции (Create — Создать, Read — прочитать, Update — модифицировать, Delete — удалить),;
  • сформировать различные запросы Query к данным с помощью предиката Predicate
  • использовать «живой» запрос @Query в SwiftUI и как его динамически настраивать,
  • эффективно «закачать» JSON данные в SwiftData хранилище без блокировки пользовательского интерфейса (UI).
Читать далее

Лекция 16. Мультиплатформенная версия EmojiArt (macOS). CS193P Весна 2021г.

Это Лекция 16 курса Stanford CS193p, весна 2021 года.

Эта лекция полностью посвящена мультиплатформенной поддержке. В частности, запускается приложение EmojiArt на Mac как собственное приложение для macOS, но при этом вы будете удивлены парой вещей. Одна из них — это какой мощный UI мы создали для работы с документами на Mac на базе документо-ориентированной SwiftUI архитектуры, а также сколько нашего iOS кода практически без модификации работает на Mac. Для той части, которая не работает, применяется несколько стратегических хитростей, способных максимально адаптировать наш код к мультиплатформенности.

На Лекции 16 профессор создает единый проект с большим количеством общего кода, и да,  с некоторыми #if os(…) — else #endif, потому что две платформы, macOS и iOS, это не одно и то же. У них не совсем один и тот же способ взаимодействия с пользователями и т. д., так что он адаптирует код к разным платформам.

Читать далее

Лекция 11. Постоянное хранение (Persistence). Обработка ошибок. CS193P Spring 2021.

Это Лекция 11 курса Stanford CS193p, весна 2021 года.

Главная тема этой Лекции — «постоянное хранение» (Persistence), то есть хранение данных в файловой системе и других местах на самом устройстве и в iCloud. Теме «постоянного хранения» сопутствуют еще две важные темы. Это формат хранения данных (самым распространенным форматом является JSON формат) и обработка ошибок, ибо операции ввода/ вывода типа записи на диск или считывания с диска, сопутствующие «постоянному хранению» (Persistence), порождают достаточное количество возможных фатальных ошибок, требующих обработки. Что касается JSON формата, то в Swift существует очень мощный Codable механизм, который позволяет практически любую структуру struct или перечисление enum превратить в  Blob данных в формате JSON.

Все 3 темы — «постоянное хранение» (Persistence), обработка ошибок  и механизм Codable — сначала рассматриваются теоретически, а затем и в демонстрационном примере. Читать далее

Лекция 10. Жесты. CS193P Spring 2021.

Это Лекция 10 курса Stanford CS193p, весна 2021 года.

На прошлой Лекции 9 мы узнали многое о многопоточности. Мы также стали специалистами по технологии Drag & Drop (перетягивание и «сброс)», теперь пришло время использовать этот механизм для формирования нашего фонового изображения background. Мы хотим иметь возможность перетаскивать (Drag) изображение из Safari, “сбрасывать” его на наш документ и формировать background нашего документа. В таком сценарии мы будет отвечать только за “сброс” (Drop), перетаскивание (Drag) выполняется Safari. Так что нам даже не нужен модификатор .onDrag, нам достаточно иметь просто .onDrop.

В нашем documentBody уже есть модификатор .onDrop, предназначенный для «сброса» наших маленьких эмодзи из палитры, теперь мы заинтересованы также в получении URL-адресов изображения .url, а также самого изображения .image. Профессор показывает, как просто можно дополнять перечень «сбрасываемых» и загружаемых объектов в модификатор .onDrop.

Но дело в том, что сброс URL-адреса изображения предполагает последующую его загрузку из интернета, а это может занять несколько секунд или даже минуту при медленном интернете. В этом случае, если не предпринять надлежащие меры, наше приложение может просто «замереть», заставить пользователя нервничать и он может буквально “убить” наше приложение, a затем вообще стереть его со своего устройства. Необходимость любой ценой сохранить отзывчивость UI для пользователя вынуждает нас использовать многопоточность, о которой мы говорили на слайдах на прошлой лекции. На этом стэнфордском курсе использование многопоточности рассматривается исключительно в этом очень важном аспекте, связанным с НЕ блокировкой UI. Мы не будем блокировать UI, если все, что может заблокировать наш UI, будет выполняться на другом потоке. О том, как это можно сделать, было рассказано на прошлой Лекции 9, а на этой Лекции профессор конкретно демонстрирует это в приложении EmojiArt.

Читать далее

Лекция 8. Анимация. Демонстрация. CS193P Spring 2021.

Это восьмая Лекция курса Stanford CS193p, весна 2021 года. Лекция 8 полностью посвящена демонстрации различных возможностей анимации в SwiftUI:

  • matchedGeometryEffect, который действует при сдаче карт
  • переворот карты, который осуществляется нашим специальным Animatable модификатором Cardify
  •  анимация нашей геометрической фигуры Shape в виде “пирога” Pie
  • неявная анимация, которая крутит эмодзи при совпадении карт
  • перетасовка карт и выбор карты представляют явную анимацию
  • запуск анимации при появлении (.onAppear) некоторых вещей
  • как задерживать анимацию карт при их сдаче
  • как диагностировать проблемы, когда у нас не происходит анимация, которую мы ожидаем при появлении на экране и уходе с экрана View, которое является частью условного предложения if-else

Читать далее

Лекция 5. Свойства Layout @ViewBuilder. CS193P Spring 2021.

Это пятая Лекция курса Stanford CS193p, весна 2021 года, и на этой лекции профессор затронул множество тем, связанных как со SwiftUI, так и непосредственно с языком программирования Swift

По SwiftUI рассматриваются четыре чрезвычайно важных темы:

  1. @State.
  2. Система Layout (управление расположением Views) в SwiftUI.
    1. HStack и VStack.
    2. LazyHStack и LazyVStack, LazyHGrid и LazyVGrid.
    3. GeometryReader. CGSize, CGFloat, CGRect.
    4. ZStack и .background и .overlay.
  3. View модификаторы
  4. @ViewBuilder. 

Что касается языка программирования Swift, то профессор Пол Хэгерти продолжает выполнять своё обещание рассказывать о Swift «с нуля» и на этой Лекции 5 освещает темы, которые проще всего показать на демонстрационных примерах:

  1. Управление доступом (private, private (set) и другие).
  2. Вычисляемые свойства (get{} и set {}).
  3. Расширения extension
  4. Функциональное программирование. 
  5. Наблюдатели свойств (Property Observer) и их отличие от вычисляемых свойств. 
  6. Оформление констант в Swift.
  7. typealias, «вывод ТИПа из контекста» (inference),  “подчеркивание” “ _” внешнего имени параметра.

Читать далее

Лекция 3. MVVM и система ТИПов в Swift. CS193P Spring 2021.

Это третья Лекция курса Stanford CS193p, весна 2021 года. На первых двух Лекциях мы много узнали о том, как создавать UI, используя SwiftUI на примере карточной игры «на запоминание» Memorize

На этой неделе мы узнаем, как “подцепить” наш UI к логике, которая знает, как играть в карточную игру “на совпадение”. Но сначала профессор рассматривает две действительно важные концептуальные идеи: MVVM и системные ТИПы языка программирования Swift.

MVVM

MVVM — это, по сути, способ организации всего кода в нашем приложении. 

Системные ТИПы в Swift, очевидно, позволяют нам делать все, что мы делаем в языке программирования Swift и, следовательно, в SwiftUI.

MVVM, как и MVC, разделяет весь код нашего приложения на код пользовательского интерфейса (UI), то есть то, что мы называем View, от логики нашего приложения, которую мы называем моделью Model.

Model —  полностью UI НЕзависима. Model вбирает в себя все данные Data и логику Logic, которые  описывают “ЧТО” делает ваше приложение. View — это то, «КАК» ваше приложение предстает перед пользователем,  Model — это то, “ЧТО”  ваше приложение делает на самом деле. Model — единственный источник ИСТИНЫ (“Truth”) для данных, которые представляют нашу игру. 

 View всегда будет отражением текущего состояния Model. View по большому счету вообще не имеет состояния State (то есть оно stateless). Ему не нужно хранить слишком много информации о состояниях State, потому что ИСТИНА (“Truth”) о состоянии игры всегда находится в Model. В демонстрационном приложении Memorize, который мы делали на прошлой неделе, всё своё время мы проводили за написанием кода для переменной var body нашего View. Этот var body всегда должен что-то возвращать на основе текущего состояния Model. Views — неизменны (immutable). Их нельзя изменить. Следовательно, нет другого способа изменить наш View, кроме как целиком перестроить var body. Следовательно, 100% того, как  выглядит View, определяется исключительно тем, что находится в  реализации переменной var body.

Мы называем этот вид кодирования декларативным, потому что мы декларируем в переменной var body, как выглядит пользовательский интерфейс (UI) нашего View. Конец истории. Это противоположно виду кодирования, к которому мы привыкли и который мы называем императивным.

Читать далее