Лучшая обработка условного рендеринга

Мы уже видели в предыдущей статье, насколько распространены необязательные представления. Мы также увидели, что логика, обрабатывающая опциональность, может иметь разных владельцев. Наконец, мы увидели, как реализовать повторно используемые необязательные представления с помощью Swift + UIKit.

На этот раз мы пропустим введение и сразу перейдем к тому, как сделать то же самое с SwiftUI на примере.

Виджет Go Premium

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

Мы собираемся показать виджет «Перейти на премиум» в разных частях приложения, где они могут нажать, чтобы запустить процесс. Но виджеты Go Premium не должны отображаться, когда пользователи уже имеют статус Premium по очевидным причинам.

Начнем с необязательного показа виджета Go Premium. Мы будем использовать простой Text, чтобы не теряться в деталях:

Как сделать виджет необязательным

Чтобы сделать виджет необязательным, нам нужно сделать несколько изменений.

Мы начинаем с извлечения экземпляра виджета из ContainerView и использования протокола, чтобы мы могли его внедрить:

И теперь мы можем реорганизовать свойство view, чтобы оно возвращало либо self, либо EmptyView в зависимости от того, имеет ли пользователь уже премиум-статус или нет.

Однако существует проблема с типом возвращаемого значения свойства view, поскольку SwiftUI.View нельзя использовать в качестве абстракции для PremiumWidget. Он использует Self, поэтому его нельзя использовать как тип. Мы также не можем вернуть some View, потому что непрозрачные типы не могут быть типом возврата требования протокола.

К счастью, SwiftUI предоставляет как минимум несколько способов сделать это. Один использует вид со стиранием текста - AnyView. Другой подход - использование Группы. Некоторые утверждают, что AnyView влияет на производительность, но вы должны сначала прочитать эту статью, а затем принять собственное решение. В любом случае, мы собираемся показать, как это можно сделать с помощью AnyView, но не стесняйтесь использовать любой из них. Отличия в коде должны быть минимальными.

Теперь у нас есть дополнительный виджет, зависящий от того, является ли пользователь премиум-классом, но здесь есть несколько существенных проблем:

  • PremiumWidget создается в любом случае.
  • Класс PremiumWidget не должен нести ответственность за то, чтобы знать, когда показывать или нет.

Извлечение экземпляра в фабричный класс

Мы собираемся переместить экземпляр PremiumWidget в класс factory, принимая во внимание следующие предпосылки:

  • Поскольку мы уже извлекли экземпляр PremiumWidget, ContainerView не следует изменять.
  • Мы не хотим, чтобы ContainerView знала, что мы используем фабричный класс.

Вот почему мы собираемся использовать шаблон прокси:

Поскольку и PremiumWidget, и PremiumWidgetFactory соответствуют PremiumWidgetProtocol, мы можем ввести любой из них, ContainerView не зная, какой из них используется. Это позволит нам удалить опциональность без изменения контейнера, в котором используется PremiumWidget.

Это может не иметь большого смысла в конкретном примере PremiumWidget, но это будет иметь место в таких случаях, как тестирование A / B, дополнительные функции, которые могут стать необязательными, и т. Д.

Заключение

Спасибо за чтение. Дайте мне знать, что вы думаете.

Спасибо Раулю Менезешу за рецензирование статьи и предложение использовать EmptyView вместо дополнительных.