Лекция 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),  “подчеркивание” “ _” внешнего имени параметра.

@State

 Ваши Views полностью доступны только для чтения. Мы предполагаем, что они просто все время рисуют нашу модель Model. Им не нужно иметь своё собственное состояние. В обычной ситуации нет никакого смысла иметь у View ничего, кроме констант let и вычисляемых переменных var c get-only стилем.  

Но есть исключения наподобие @ObservedObject и @State. @State нам нужен исключительно для внутренней работы нашего View, временных вещей, которые иногда происходят и мы должны их отслеживать. Поэтому все эти @State переменные var являются private.

Управление доступом

Управление доступом — это защита ваших внутренних структур данных от другого кода, который не должен смотреть на них и особенно модифицировать его. По сути, любая функция func или переменная var в любом создаваемом вами коде, которые вы хотите использовать только внутри этой структуры struct или класса class, должны быть помечены как private или, возможно, private (set). Помимо тех функций func и переменных var, которые участвуют в API (программном интерфейсе), специально предоставляемым людям для использования этой структуры struct или класса class. Есть еще несколько ключевых слов в Мире управления доступом. Например, есть public, что противоположно private, open, что очень похоже на public, они используется только для библиотек. Есть еще один способ доступа, internal, который вы также можете увидеть. 

Пол Хэгерти проходит по всему коду нашего демонстрационного примера (ViewModel, Model, View) и проставляет нужный уровень доступа.

Вычисляемые Свойства, расширения extension и Наблюдатели Свойства (Property Observer)

Профессор показывает, как сочетание вычисляемых свойств (computed property) и расширений extension с функциональным программирование позволяет не только существенно сократить код, но и улучшить его читабельность.

В большинстве случаев люди путают Наблюдателей Свойства (Property Observers) willSet {…} и didSet {…} с вычисляемыми свойствами (computed properties). Профессор показывает Наблюдателей Свойства (Property Observers)  сразу после вычисляемых свойств (computed properties), чтобы студенты поняли существенную разницу между ними.

Наблюдатели Свойства (Property Observers)  — это абсолютно другая вещь, чем вычисляемые свойства (computed properties), хотя имеют схожий синтаксис. С помощью Наблюдателей Свойства Swift предоставляет действительно классную возможность ВАМ участвовать в формировании кода, когда структура struct фактически меняется.

Расположение на экране: Layout

 Но одной из центральных тем Лекции 5 безусловно является Layout, то есть, как мы решаем, ГДЕ располагать все наши Views на экране. Способ, каким SwiftUI делает это, — удивительно прост. Это одна из наиболее элегантных вещей во всём SwiftUI. Нужно всего 4 шага, чтобы расположить что-либо с помощью SwiftUI  и они подробно описаны в Лекции 5.

Подробно рассматривается, как распределяют своё пространство стеки HStack и VStack, ZStack, «ленивые» стеки LazyHStack и LazyVStack, «ленивые» «сетки» LazyHGrid и LazyVGrid, почему ForEach “перекладывает” распределение пространства между своими Views на другие контейнеры. например, на стеки HStack и VStack, что такое Spacer и Divider, что такое «гибкие» и «негибкие» Views, что такое .layoutPriority, что такое модификаторы и как они участвуют в Layout, что такое GeometryReader, как участвует SafeArea в Layout.

 Показывается, как можно применить все это для того, чтобы размер шрифта, используемого для рисования наших эмодзи (смайлики) лучше подходил под размер карты игры Memorize

ViewModifier

Мы использовали модификаторы ViewModifiers повсюду в нашей игре Memorize: aspectRatio, padding, font, foregroundColor. Все они — ViewModifiers. Они модифицируют View и возвращают новое View, которое является модифицированной версией View, для которого вызывался модификатор.
Вот, собственно, что делают модификаторы ViewModifiers.

На этой Лекции мы видели  .background и .overlay — это модификаторы View, которые действуют очень похоже как контейнеры Views.

Большинству модификаторов, какой угодно размер ни дай, они просто передают его View, который они модифицируют. Но некоторые модификаторы на самом деле задействованы в процессе Layout размещения Views. Самые очевидные модификаторы этого рода — .padding и .aspectRatio, которые профессор очень детально рассматривает на этой Лекции.

@ViewBuilder

Рассматривается очень важная концепция @ViewBuilder, которую мы использовали повсюду в первые три недели этого курса. @ViewBuilder был аргументом, который передается в ZStack, ForEach и LazyVGrid и во всё, что является списком  Views.

В этой Лекции пришло время четко понять, что @ViewBuilder основан на общей технологии, которая была добавлена в Swift для поддержания списко-ориентированного синтаксиса. Как только у нас появляется этот механизм, мы очень быстро обнаруживаем, что существует множество мест, где мы бы хотели иметь список Views.

Всё, к чему применяется  @ViewBuilder, будь то функция или аргумент функции, меняет способ, каким компилятор рассматривает содержимое фигурных скобок {…} этой функции, он интерпретирует его как список Views. Он по-прежнему комбинирует эти Views в одно View, и это  по-прежнему функция, которая возвращает единственное Viewsome View, но компилятор выполняет эту комбинацию списка Views для вас “за кулисами” без необходимости вам об этом беспокоиться.

Так что любую функцию или вычисляемую read-only(только для чтения) переменную var, такую как var body, например, можно пометить с помощью @ViewBuilder. Внутри @ViewBuilders нам разрешено в основном делать следующие вещи: иметь список Views, использовать if-else, switch и if let для выбора, какие Views включать в список.

Код демонстрационного примера для Лекции 5 находится на Github для iOS 14 в папке Memorize L5.

Русскоязычный неавторизованный конспект Лекции 5, иллюстрированный, хронометрированный и представленный в виде PDF-файла, который можно скачать и использовать offline, а также в формате Google Doc доступны на платной основе.