SwiftyUserDefaults для Swift: полное руководство с примерами

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Что такое SwiftyUserDefaults и зачем она нужна?

SwiftyUserDefaults — это легковесная, но мощная библиотека-обёртка для стандартного класса UserDefaults в Swift. Если вы когда-либо работали с UserDefaults напрямую, то знаете, что это может быть утомительно: вам нужно писать много шаблонного кода для сохранения и извлечения значений, явно указывать тип данных, использовать строковые ключи (что чревато опечатками) и обрабатывать опциональные значения.

SwiftyUserDefaults решает все эти проблемы. Она предоставляет:

  • Статическую типизацию: компилятор проверяет типы, что исключает ошибки времени выполнения.
  • Глобальный доступ: доступ к значениям через удобное свойство Defaults.
  • Поддержку кастомных типов: вы можете сохранять любые свои структуры и классы, реализовав протокол DefaultsSerializable.
  • Синтаксический сахар: работа с UserDefaults становится похожей на работу с обычными свойствами.
  • Безопасность: исчезает риск опечататься в строковом ключе.

Библиотека идеально подходит для хранения небольших объёмов данных: настроек приложения, состояния пользовательского интерфейса, токенов аутентификации и т.д. Она не предназначена для хранения больших массивов данных — для этого есть Core Data, Realm или файлы.

Установка

SwiftyUserDefaults распространяется через Swift Package Manager (SPM), CocoaPods и Carthage. Рассмотрим два самых популярных способа.

Swift Package Manager (рекомендуется)

  1. В Xcode откройте меню: File → Add Packages...
  2. Вставьте URL репозитория: https://github.com/sunshinejr/SwiftyUserDefaults.git
  3. Выберите версию (рекомендуется последняя стабильная) и нажмите Add Package.
  4. Убедитесь, что пакет добавлен в вашу цель (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 для хранения данных. Код стал чистым,

Рекомендаций