Найти в Дзене
Nuances of programming

Понимание врапперов в Swift

Источник: Nuances of Programming Наряду со многими новыми функциями, которые появились в Swift 5.1, одна из самых интересных —  это врапперы свойств. По сути врапперы находятся между поведением свойств и их хранением. Врапперы свойств определяются с помощью struct, class, or enum. Также они могут применяться, если мы задаем свойства внутри этих типов. Swift уже предоставлял несколько встроенных врапперов в предыдущих версиях, например lazy, @NSCopying, но с врапперами свойств разработчик может внедрять собственные без усложнения языка. О том, как это работает, можно прочесть в документации по ссылке. Врапперы свойств активно используются в SwiftUI. Фреймворк предоставляет множество врапперов, например: Врапперы свойств не ограничены только SwiftUI. Со Swift 5.1 можно создавать пользовательские врапперы свойств! Вот, что можно делать , используя пользовательские врапперы: Это всего лишь несколько примеров врапперов, которые можно создавать; возможности по сути безграничны! Давайте созд
Оглавление

Источник: Nuances of Programming

Наряду со многими новыми функциями, которые появились в Swift 5.1, одна из самых интересных —  это врапперы свойств. По сути врапперы находятся между поведением свойств и их хранением. Врапперы свойств определяются с помощью struct, class, or enum. Также они могут применяться, если мы задаем свойства внутри этих типов.

Swift уже предоставлял несколько встроенных врапперов в предыдущих версиях, например lazy, @NSCopying, но с врапперами свойств разработчик может внедрять собственные без усложнения языка. О том, как это работает, можно прочесть в документации по ссылке.

Врапперы свойств активно используются в SwiftUI. Фреймворк предоставляет множество врапперов, например:

  • @State. Его значение привязывается к представлению, в котором оно объявлено.
  • @Binding. Предается вниз от родительского свойства State с использованием$ projectedValue.
  • @ObservedObject. Похож на@State, но используется для свойства, которое соотносится с протоколом ObservableObject. ObservableObject должен быть типом class и обновлять представление, когда изменяются свойства, помеченные @Published.
  • @Published. Этот враппер используется для свойств, заявленных в ObservableObject. Всякий раз, когда значение меняется, враппер вызывает метод objectWillChange, чтобы представление реагировало на изменения.
  • @EnvironmentObject. Похож на @ObservedObject, но может использоваться для обмена данными между различными представлениями сверху вниз по иерархии без передачи явного свойства дочернему представлению.
  • @Environment. Используется для внедрения и коррекции общесистемной конфигурации —  цветовой схемы системы, направления макета, размера содержимого — внутри представления.

Врапперы свойств не ограничены только SwiftUI. Со Swift 5.1 можно создавать пользовательские врапперы свойств! Вот, что можно делать , используя пользовательские врапперы:

  • Преобразовывать значение после того, как оно уже было назначено.
  • Задавать минимальные и максимальные границы значения.
  • Передавать свойству дополнительное значение.
  • Создавать враппер, ведущий себя как делегат, скрывающий детали реализации API.

Это всего лишь несколько примеров врапперов, которые можно создавать; возможности по сути безграничны! Давайте создадим несколько врапперов и посмотрим, как с их помощью можно упростить код.

Использование врапперов свойств в двух словах

Создать новый враппер очень просто:

  • Объявите ключевое слово @propertyWrapper до того, как объявить тип, в котором хотите использовать враппер свойства. Это может быть struct, class или enum.
  • Мы должны реализовать свойство wrappedValue. Обычно в этом свойстве объявляются пользовательские setter и getter. Это свойство может быть computed или stored.
  • При присвоении свойству значения при объявлении, блок инициализации передаст wrappedValue . Также можно создать пользовательский блок инициализации с дополнительными свойствами. Ниже в примерах с враппером @Ranged мы рассмотрим это подробнее. 
  • Можно задать дополнительное свойство projectedValue любого типа, с помощью префикса $ из свойства.

Чтобы использовать его, мы добавляем префиксом @ к врапперу, когда объявляем свойство в типе.

Теперь давайте внедрим пользовательские врапперы! 

Преобразование значения свойства 

-2

Для этого @Uppercased враппера, мы хотим убедиться, что String всегда выводится в верхнем регистре, когда внутри свойства задано значение. Вот что нужно сделать для реализации: 

  • Сохраняем нужную строку внутри свойства, названного text. 
  • Необходимое wrappedValue свойство — вычисляемое. Всякий раз, когда мы задаем значение, оно будет храниться в свойстве text. Каждый раз при получении свойства, значение будет возвращено в верхнем регистре. 
  • Создаем блок инициализации wrappedValue и назначаем его свойству text при первой инициализации враппера. 
  • Чтобы запустить, просто добавляем ключевое слово @Uppercased перед свойством.

Обозначение минимальной и максимальной границ числового значения 

-3

@Ranged враппер можно использовать для фиксации значения числа, задав минимальную и максимальную границы значения. Каждый раз, когда присваивается значение, производится сравнение, и значение присваивается на основании следующих условий: 

  • Если новое присваиваемое значение больше максимальной границы, в свойстве сохраняется максимальное значение.
  • Если новое значение меньше минимальной границы, в свойстве сохраняется минимальное значение.
  • Если условия не пересекаются, в свойстве сохраняется новое значение. 

Чтобы принять минимальный и максимальный параметры, создается пользовательский блок инициализации. Когда мы объявляем свойство, нам также нужно передать значения максимума и минимума после объявления @Ranged.

Свойство Project Date для отформатированной в ISO8601 строки

-4

Врапперы свойств можно использовать, чтобы передавать другое значение любого типа, используя свойство projectedValue с префиксом $. Для ISO8601DateFormatter используется статичный private ISO8601DateFormatter. Каждый раз при чтении projectedValue преобразовывает дату из сохраненного свойства wrappedValue.

Враппер свойства NSLocalizedString API 

-5

Враппер свойства @Localizable используется для оборачивания NSLocalizedString API. Когда свойство объявлено с использованием ключевого слова @Localizable, значение будет сохранено в приватном свойстве key и будет использовано каждый раз, когда wrappedValue доступно при передаче NSLocalizedString(key:comment:) блоку инициализации для получения локализованной строки из приложения. 

Оборачивание UserDefaults API 

-6

UserDefaults API может быть очень громоздким при сохранении и извлечении значений по умолчанию. Его можно упростить созданием враппера, который спрячет выполнение вызовов API.

Враппер @UserDefault принимает 2 параметра в блоке инициализации, key и initialValue в том случае, если значение ключа не доступно в UserDefaults . Сам wrappedValue — это враппер-вычислитель. Он использует сохраненный key каждый раз, когда задано значение. При чтении свойства, key используется для получения значения generic. Если значение не доступно, вместо него вернется initialValue. 

Заключение

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

Код на Github.

Читайте также:

Читайте нас в телеграмме и vk

Перевод статьи Alfian Losari: Understanding Property Wrappers in Swift By Examples