Что такое SwiftyUserDefaults и зачем она нужна?
SwiftyUserDefaults — это легковесная, но мощная библиотека-обёртка для стандартного класса UserDefaults в Swift. Если вы когда-либо работали с UserDefaults напрямую, то знаете, что это может быть утомительно: вам нужно писать много шаблонного кода для сохранения и извлечения значений, явно указывать тип данных, использовать строковые ключи (что чревато опечатками) и обрабатывать опциональные значения.
SwiftyUserDefaults решает все эти проблемы. Она предоставляет:
- Статическую типизацию: компилятор проверяет типы, что исключает ошибки времени выполнения.
- Глобальный доступ: доступ к значениям через удобное свойство
Defaults. - Поддержку кастомных типов: вы можете сохранять любые свои структуры и классы, реализовав протокол
DefaultsSerializable. - Синтаксический сахар: работа с UserDefaults становится похожей на работу с обычными свойствами.
- Безопасность: исчезает риск опечататься в строковом ключе.
Библиотека идеально подходит для хранения небольших объёмов данных: настроек приложения, состояния пользовательского интерфейса, токенов аутентификации и т.д. Она не предназначена для хранения больших массивов данных — для этого есть Core Data, Realm или файлы.
Установка
SwiftyUserDefaults распространяется через Swift Package Manager (SPM), CocoaPods и Carthage. Рассмотрим два самых популярных способа.
Swift Package Manager (рекомендуется)
- В Xcode откройте меню:
File → Add Packages... - Вставьте URL репозитория:
https://github.com/sunshinejr/SwiftyUserDefaults.git - Выберите версию (рекомендуется последняя стабильная) и нажмите
Add Package. - Убедитесь, что пакет добавлен в вашу цель (target).
CocoaPods
Добавьте в ваш Podfile:
target 'YourAppTarget' do
use_frameworks!
pod 'SwiftyUserDefaults', '~> 5.3'
end
Затем выполните pod install.
После установки импортируйте библиотеку в нужном файле:
import SwiftyUserDefaults
Быстрый старт
Давайте сразу перейдём к коду. Вот как выглядит типичный сценарий работы с UserDefaults без SwiftyUserDefaults и с ним.
Без SwiftyUserDefaults (стандартный подход)
// Сохранение
UserDefaults.standard.set("John", forKey: "user_name")
UserDefaults.standard.set(25, forKey: "user_age")
UserDefaults.standard.set(true, forKey: "is_logged_in")
// Чтение
let name = UserDefaults.standard.string(forKey: "user_name") ?? ""
let age = UserDefaults.standard.integer(forKey: "user_age")
let isLoggedIn = UserDefaults.standard.bool(forKey: "is_logged_in")
С SwiftyUserDefaults
// Определяем ключи (можно в отдельном файле)
extension DefaultsKeys {
var userName: DefaultsKey<String> { .init("user_name") }
var userAge: DefaultsKey<Int> { .init("user_age") }
var isLoggedIn: DefaultsKey<Bool> { .init("is_logged_in") }
}
// Сохранение
Defaults[\.userName] = "John"
Defaults[\.userAge] = 25
Defaults[\.isLoggedIn] = true
// Чтение
let name: String = Defaults[\.userName]
let age: Int = Defaults[\.userAge]
let isLoggedIn: Bool = Defaults[\.isLoggedIn]
print("\(name) is \(age) years old. Logged in: \(isLoggedIn)")
Как видите, код стал чище, типы проверяются на этапе компиляции, а ключи определены в одном месте.
Основные методы и функции
Рассмотрим 10 ключевых возможностей библиотеки с примерами.
1. Defaults[\.key] — получение и установка значения
Что делает: Основной способ доступа к значению. Использует key path для безопасной типизации.
Параметры: key path, определённый в расширении DefaultsKeys.
Пример:
extension DefaultsKeys {
var username: DefaultsKey<String> { .init("username") }
}
// Установка
Defaults[\.username] = "Alice"
// Получение
let username: String = Defaults[\.username]
print(username) // "Alice"
2. Defaults.hasKey(\.key) — проверка существования ключа
Что делает: Проверяет, существует ли значение для указанного ключа в UserDefaults.
Параметры: key path.
Возвращает: Bool.
Пример:
if Defaults.hasKey(\.username) {
print("Username is set: \(Defaults[\.username])")
} else {
print("Username is not set")
}
3. Defaults.remove(\.key) — удаление значения
Что делает: Удаляет значение для указанного ключа из UserDefaults.
Параметры: key path.
Пример:
Defaults[\.username] = "TempUser"
Defaults.remove(\.username)
print(Defaults[\.username]) // "" (пустая строка, так как тип String)
4. Defaults[\.key, defaultValue: value] — значение по умолчанию
Что делает: Позволяет задать значение по умолчанию, если ключ отсутствует.
Параметры: key path, defaultValue — значение, которое будет возвращено, если ключ не найден.
Пример:
let theme = Defaults[\.theme, defaultValue: "light"]
print(theme) // "light", если ключ 'theme' не был установлен
5. Defaults.observe(\.key) — наблюдение за изменениями
Что делает: Позволяет подписаться на изменения значения ключа. Возвращает объект NSKeyValueObservation, который нужно удерживать.
Параметры: key path, замыкание (callback), которое вызывается при изменении.
Пример:
var observation = Defaults.observe(\.username) { update in
print("Username changed from '\(update.oldValue)' to '\(update.newValue)'")
}
Defaults[\.username] = "Bob"
// В консоли: Username changed from 'Alice' to 'Bob'
6. Defaults[\.key].isNil — проверка на nil для опциональных типов
Что делает: Позволяет проверить, является ли значение nil (только для опциональных типов).
Параметры: key path с опциональным типом (например, DefaultsKey<String?>).
Пример:
extension DefaultsKeys {
var nickname: DefaultsKey<String?> { .init("nickname") }
}
if Defaults[\.nickname].isNil {
print("Nickname is nil")
} else {
print("Nickname is \(Defaults[\.nickname]!)")
}
7. Defaults[\.key].isNotNil — обратная проверка
Что делает: Проверяет, что значение не является nil.
Пример:
if Defaults[\.nickname].isNotNil {
print("Nickname is set")
}
8. Defaults[\.key].clear() — сброс к значению по умолчанию
Что делает: Удаляет значение из UserDefaults, после чего при следующем чтении будет возвращено значение по умолчанию для типа (0 для Int, "" для String и т.д.).
Пример:
Defaults[\.username] = "Charlie"
Defaults[\.username].clear()
print(Defaults[\.username]) // ""
9. Defaults.removeAll() — удаление всех значений
Что делает: Очищает все значения, сохранённые через SwiftyUserDefaults (но не трогает данные, сохранённые напрямую через UserDefaults).
Пример:
Defaults[\.username] = "Dave"
Defaults[\.userAge] = 30
Defaults.removeAll()
print(Defaults[\.username]) // ""
print(Defaults[\.userAge]) // 0
10. DefaultsSerializable — сохранение кастомных типов
Что делает: Позволяет сохранять и загружать свои структуры или классы. Нужно реализовать протокол DefaultsSerializable.
Пример:
struct User: Codable, DefaultsSerializable {
let id: Int
var name: String
var email: String
}
extension DefaultsKeys {
var currentUser: DefaultsKey<User?> { .init("current_user") }
}
// Сохранение
let user = User(id: 1, name: "Eve", email: "eve@example.com")
Defaults[\.currentUser] = user
// Загрузка
if let loadedUser = Defaults[\.currentUser] {
print("Loaded user: \(loadedUser.name)")
}
Реальный практический пример
Представьте, что мы разрабатываем приложение-погоду. Нам нужно сохранять настройки пользователя: выбранный город, единицы измерения (Цельсий/Фаренгейт) и последнюю обновлённую дату. Вот как это можно реализовать с помощью SwiftyUserDefaults.
import SwiftyUserDefaults
// 1. Определяем ключи
extension DefaultsKeys {
var selectedCity: DefaultsKey<String> { .init("selected_city") }
var isCelsius: DefaultsKey<Bool> { .init("is_celsius") }
var lastUpdateDate: DefaultsKey<Date?> { .init("last_update_date") }
}
// 2. Класс-менеджер настроек
final class SettingsManager {
static let shared = SettingsManager()
var selectedCity: String {
get { Defaults[\.selectedCity, defaultValue: "Moscow"] }
set { Defaults[\.selectedCity] = newValue }
}
var isCelsius: Bool {
get { Defaults[\.isCelsius, defaultValue: true] }
set { Defaults[\.isCelsius] = newValue }
}
var lastUpdateDate: Date? {
get { Defaults[\.lastUpdateDate] }
set { Defaults[\.lastUpdateDate] = newValue }
}
func resetAllSettings() {
Defaults.removeAll()
}
func updateLastUpdateDate() {
lastUpdateDate = Date()
}
}
// 3. Использование в приложении
class WeatherViewController: UIViewController {
let settings = SettingsManager.shared
override func viewDidLoad() {
super.viewDidLoad()
print("Current city: \(settings.selectedCity)")
print("Using Celsius: \(settings.isCelsius)")
if let lastUpdate = settings.lastUpdateDate {
print("Last update: \(lastUpdate)")
} else {
print("No updates yet")
}
}
@IBAction func changeCityTapped() {
settings.selectedCity = "London"
settings.updateLastUpdateDate()
print("City changed to London")
}
@IBAction func toggleUnitsTapped() {
settings.isCelsius.toggle()
print("Units changed. Celsius: \(settings.isCelsius)")
}
@IBAction func resetTapped() {
settings.resetAllSettings()
print("All settings reset to defaults")
}
}
В этом примере мы создали централизованный менеджер настроек, который использует SwiftyUserDefaults для хранения данных. Код стал чистым,
Также в библиотеке
Миграции баз данных в Node.js: Обзор инструментов и примеры
Планировщик задач Swift: GCD, OperationQueue и Timer на iOS/macOS