Больше никаких шаблонных кодов и повысьте возможность повторного использования

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

Вы будете использовать оболочку UserDefaults для отслеживания статуса включения / выключения автоматического входа, а также имени пользователя. Вот как обычно выглядит ваша UserDefaults оболочка:

С помощью оболочки свойств, представленной в Swift 5.1, вы можете упростить свою оболочку UserDefaults следующим образом:

Довольно круто, правда? Хотите узнать больше? Читать дальше…

Что такое Property Wrapper?

Прежде чем мы углубимся в подробности, давайте кратко познакомимся с тем, что такое оболочка свойств.

По сути, оболочка свойства - это общая структура данных, которая может перехватывать доступ для чтения / записи свойства, что позволяет добавлять настраиваемое поведение во время операции чтения / записи свойства.

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

Вы можете создать оболочку свойств с именем Printable, как показано ниже:

Как видно из приведенного выше кода, оболочка свойств такая же, как и любой другой struct в Swift. Однако wrappedValue является обязательным при определении оболочки свойства.

Блок wrappedValue get и set - это то место, где вы можете перехватить и выполнить желаемую операцию. В этом примере добавляется оператор печати для вывода значения get или set.

Вот как можно использовать оболочку свойств Printable:

Обратите внимание, что мы используем символ @ для объявления переменной name, заключенной в оболочку свойства. Если вы попробуете приведенный выше код на своей игровой площадке Xcode, вы увидите вывод консоли, как показано ниже:

Set value: Adidas
Get value: Adidas

Обертка UserDefaults

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

Используя концепцию, которую мы обсуждали выше, вы можете легко преобразовать оболочку свойства Printable в оболочку свойства, которая будет записывать или читать из UserDefaults во время операции чтения / записи свойства.

Здесь мы назвали нашу оболочку свойств Storage. Он имеет два свойства: key и defaultValue.

key будет ключом, который будет использоваться при чтении и записи в UserDefaults, а defaultValue - это значение, которое нужно вернуть, если в UserDefaults нет значения.

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

Обратите внимание, как можно инициализировать оболочку свойств Storage с помощью key и defaultValue.

При этом оболочка UserDefaults, наконец, готова к использованию. Посмотрим на это в действии:

На этом этапе давайте попробуем добавить переменную enableAutoLogin в нашу UserDefaults оболочку.

Однако вы заметите, что произошли следующие две ошибки:

Cannot convert value of type ‘Bool’ to expected argument type ‘String’
Property type ‘Bool’ does not match that of the ‘wrappedValue’ property of its wrapper type ‘Storage’

Это связано с тем, что наша оболочка свойств в настоящее время поддерживает только тип данных String. Чтобы исправить обе ошибки, нам нужно сделать нашу оболочку свойств универсальной.

Делаем Property Wrapper универсальным

Чтобы сделать оболочку свойств универсальной, мы должны изменить тип данных wrappedValue оболочки свойств с String на общий тип T.

Кроме того, нам нужно будет обновить блок wrappedValue get, чтобы использовать общий способ чтения из UserDefaults. Вот обновленная оболочка свойств:

Благодаря универсальной оболочке свойств наша оболочка UserDefaults теперь может без проблем хранить логическое значение.

Хранение пользовательских объектов

На данный момент наша оболочка UserDefaults может хранить любой базовый тип данных, например String, Bool, Int, Float, Array и т. Д.

Но что, если нам нужно сохранить настраиваемый объект? В настоящее время мы столкнемся с ошибкой, если попытаемся сохранить настраиваемый объект. В этом разделе давайте сделаем нашу UserDefaults оболочку более привлекательной, включив в нее поддержку настраиваемых объектов.

Идея здесь проста: мы будем хранить настраиваемый объект как данные в UserDefaults. Для этого мы должны обновить общий тип Storage оболочки свойств T, чтобы он соответствовал протоколу Codable.

После этого в блоке wrappedValue set мы будем использовать JSONEncoder для преобразования настраиваемого объекта в данные и записи его в UserDefaults.

Между тем, в блоке wrappedValue get мы будем использовать JSONDecoder для преобразования данных, полученных из UserDefaults, обратно в нужный тип данных.

Вот обновленная оболочка свойств Storage:

Чтобы увидеть, как можно использовать обновленную оболочку свойств Storage, давайте взглянем на следующий пример.

Представьте, что вам нужно сохранить информацию о пользователе, возвращаемую сервером после успешного входа в систему.

Во-первых, вам понадобится структура для хранения информации о пользователе, возвращаемой сервером. Структура должна соответствовать протоколу Codable, чтобы ее можно было преобразовать в данные и сохранить в UserDefaults.

Следующим шагом является объявление объекта User в оболочке UserDefaults:

Вот и все! Обертка UserDefaults теперь может хранить пользовательские объекты.

Хранение зашифрованной строки

Мы прошли долгий путь, сделав нашу UserDefaults оболочку универсальной и способной хранить практически все, что мы пожелаем.

Но подождите, а что, если вам нужно сохранить пароль пользователя или какие-либо конфиденциальные данные с помощью оболочки UserDefaults?

В настоящее время все строки, которые хранятся в нашей UserDefaults оболочке, представляют собой простой текст, и все мы знаем, что хранить пароли в виде простого текста - крайне плохая практика!

Для этого мы можем использовать концепцию, которую мы только что обсудили, создать другую оболочку свойства, которая зашифрует ее значение перед установкой в ​​UserDefaults. Мы назовем эту оболочку свойств EncryptedStringStorage.

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

Заключение

Используя оболочку свойств, представленную в Swift 5.1, мы сократили много шаблонного кода в нашей оболочке UserDefaults.

Кроме того, оболочку свойств Storage и оболочку свойств EncryptedStringStorage также можно повторно использовать в других проектах.

В следующий раз, когда вам понадобится создать оболочку UserDefaults, попробуйте метод оболочки свойств, я уверен, вам она понравится.

Вы можете найти полный исходный код здесь.

Надеюсь, эта статья окажется для вас полезной. Не стесняйтесь оставлять комментарии, если у вас есть какие-либо вопросы или мысли относительно оболочки UserDefaults.

Спасибо за чтение и удачного кодирования!