Лучшая обработка условного рендеринга
Мы уже видели в предыдущей статье, насколько распространены необязательные представления. Мы также увидели, что логика, обрабатывающая опциональность, может иметь разных владельцев. Наконец, мы увидели, как реализовать повторно используемые необязательные представления с помощью 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
вместо дополнительных.