UserDefaults and app preferences

Sofia Martinez Jan 2026
1 tab
import Foundation

enum UserDefaultsKey: String {
    case username
    case isFirstLaunch
    case lastSyncDate
    case theme
    case fontSize
    case notificationsEnabled
    case selectedLanguage
}

class UserDefaultsManager {
    static let shared = UserDefaultsManager()
    private let defaults = UserDefaults.standard

    private init() {}

    // MARK: - Basic Types
    func set<T>(_ value: T, forKey key: UserDefaultsKey) {
        defaults.set(value, forKey: key.rawValue)
    }

    func get<T>(forKey key: UserDefaultsKey) -> T? {
        return defaults.object(forKey: key.rawValue) as? T
    }

    func remove(forKey key: UserDefaultsKey) {
        defaults.removeObject(forKey: key.rawValue)
    }

    // MARK: - Convenience Properties
    var username: String? {
        get { get(forKey: .username) }
        set { set(newValue, forKey: .username) }
    }

    var isFirstLaunch: Bool {
        get { get(forKey: .isFirstLaunch) ?? true }
        set { set(newValue, forKey: .isFirstLaunch) }
    }

    var lastSyncDate: Date? {
        get { get(forKey: .lastSyncDate) }
        set { set(newValue, forKey: .lastSyncDate) }
    }

    // MARK: - Codable Support
    func setCodable<T: Codable>(_ value: T, forKey key: String) {
        if let encoded = try? JSONEncoder().encode(value) {
            defaults.set(encoded, forKey: key)
        }
    }

    func getCodable<T: Codable>(forKey key: String) -> T? {
        guard let data = defaults.data(forKey: key) else { return nil }
        return try? JSONDecoder().decode(T.self, from: data)
    }

    // MARK: - App Group Support
    static func groupDefaults(suiteName: String) -> UserDefaults? {
        return UserDefaults(suiteName: suiteName)
    }
}

// MARK: - Type-safe wrapper
struct AppSettings: Codable {
    var theme: String
    var fontSize: Double
    var notificationsEnabled: Bool
    var selectedLanguage: String

    static func load() -> AppSettings {
        UserDefaultsManager.shared.getCodable(forKey: "appSettings") ?? AppSettings.default
    }

    func save() {
        UserDefaultsManager.shared.setCodable(self, forKey: "appSettings")
    }

    static var `default`: AppSettings {
        AppSettings(
            theme: "system",
            fontSize: 16,
            notificationsEnabled: true,
            selectedLanguage: "en"
        )
    }
}
1 file · swift Explain with highlit

UserDefaults provides simple key-value storage for app preferences and settings. It persists basic types like strings, numbers, bools, dates, and data automatically. I use UserDefaults for user preferences, app state, and feature flags—never for sensitive data like passwords. The standard suite UserDefaults.standard is most common. App groups share defaults between apps and extensions with UserDefaults(suiteName:). SwiftUI's @AppStorage property wrapper creates reactive bindings to UserDefaults. I create type-safe wrappers with enums for keys to prevent typos. For complex objects, I encode to Data with Codable. UserDefaults syncs to disk periodically, making it reliable for non-critical data.