Skip to content

UserDefaults

UserDefaults is a lightweight, built-in mechanism in iOS for storing small amounts of user data, such as preferences or settings, persistently across app launches. It provides a simple key-value storage system, ideal for saving basic data types like booleans, strings, numbers, and property list objects. This document covers the usage of UserDefaults in UIKit-based iOS applications.

Purpose

  • Persistent Storage: Save user preferences or app state between sessions.
  • Simple Interface: Store and retrieve key-value pairs without complex setup.
  • Cross-Session Access: Access data globally within the app or across apps in the same app group.

Key Features

  • Standard Instance: UserDefaults.standard provides the default storage for the app.
  • Supported Types: Stores property list types (String, Int, Double, Bool, Data, Array, Dictionary) and Date.
  • App Groups: Supports shared storage for apps and extensions via app groups.
  • Synchronization: Automatically or manually synchronizes data to disk.

Basic Usage

UserDefaults is accessed via the UserDefaults class, typically using the standard instance. Data is stored and retrieved using keys.

Example: Storing and Retrieving Data

swift
import UIKit

class ViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        
        // Store data
        let defaults = UserDefaults.standard
        defaults.set("John Doe", forKey: "username")
        defaults.set(true, forKey: "isDarkModeEnabled")
        defaults.set(42, forKey: "userScore")
        
        // Retrieve data
        if let username = defaults.string(forKey: "username") {
            print("Username: \(username)")
        }
        let isDarkMode = defaults.bool(forKey: "isDarkModeEnabled")
        print("Dark Mode: \(isDarkMode)")
        let score = defaults.integer(forKey: "userScore")
        print("Score: \(score)")
    }
}

Key Points

  • Setting Values: Use set(_:forKey:) to store supported types.
  • Retrieving Values: Use type-specific methods like string(forKey:), bool(forKey:), integer(forKey:), or object(forKey:) for generic access.
  • Default Values: Methods like string(forKey:) return nil if the key doesn’t exist; use optional binding or default values.
  • Keys: Use unique, descriptive strings to avoid conflicts.

Advanced Features

Storing Complex Data

UserDefaults supports property list-compatible collections (Array, Dictionary) and Data for custom objects (via serialization).

Example: Storing an Array

swift
let defaults = UserDefaults.standard
let scores = [100, 200, 300]
defaults.set(scores, forKey: "highScores")

if let retrievedScores = defaults.array(forKey: "highScores") as? [Int] {
    print("High Scores: \(retrievedScores)")
}

Example: Storing Custom Objects

Custom objects must be serialized to Data using NSKeyedArchiver or JSON encoding.

swift
struct User: Codable {
    let name: String
    let age: Int
}

let user = User(name: "Jane", age: 30)
if let encodedData = try? JSONEncoder().encode(user) {
    UserDefaults.standard.set(encodedData, forKey: "userData")
}

if let data = UserDefaults.standard.data(forKey: "userData"),
   let decodedUser = try? JSONDecoder().decode(User.self, from: data) {
    print("User: \(decodedUser.name), Age: \(decodedUser.age)")
}

Synchronization

UserDefaults automatically saves changes periodically, but you can force synchronization:

swift
UserDefaults.standard.synchronize() // Rarely needed in modern iOS

Note: synchronize() is largely deprecated as iOS handles saving automatically, but it can be used for immediate persistence in rare cases.

App Groups

For shared data between an app and its extensions, use an app group:

swift
if let groupDefaults = UserDefaults(suiteName: "group.com.example.app") {
    groupDefaults.set("Shared Data", forKey: "sharedKey")
    if let value = groupDefaults.string(forKey: "sharedKey") {
        print("Shared: \(value)")
    }
}

Configure the app group in Xcode’s “Capabilities” for both the app and extension.

Removing Data

Remove specific keys or all data:

swift
UserDefaults.standard.removeObject(forKey: "username")
UserDefaults.standard.removePersistentDomain(forName: Bundle.main.bundleIdentifier!) // Reset all

Observing Changes

Use KVO (Key-Value Observing) or notifications to monitor changes:

swift
NotificationCenter.default.addObserver(
    forName: UserDefaults.didChangeNotification,
    object: nil,
    queue: .main
) { _ in
    print("UserDefaults changed")
}

Best Practices

  • Small Data: Use UserDefaults for small, simple data (e.g., settings, flags); use Core Data or file storage for large datasets.
  • Key Naming: Use clear, namespaced keys (e.g., com.example.setting) to avoid conflicts.
  • Type Safety: Use type-specific retrieval methods to avoid casting errors.
  • App Groups: Enable app groups for shared data in extensions or watchOS apps.
  • Performance: Avoid frequent writes to UserDefaults in performance-critical code.
  • Security: Do not store sensitive data (e.g., passwords) in UserDefaults; use Keychain instead.
  • Testing: Verify data persistence across app launches and device restarts.

Limitations

  • Data Types: Only property list types and Data are supported natively.
  • Size: Not suitable for large data (e.g., images or large datasets).
  • Security: Data is stored unencrypted; use Keychain for sensitive information.
  • Thread Safety: UserDefaults is thread-safe, but avoid heavy operations on the main thread.

Summary

UserDefaults provides a simple, efficient way to store small amounts of persistent data in UIKit apps. It supports basic types, collections, and serialized custom objects, with features like app groups for shared storage. While ideal for user preferences, it’s not suited for large or sensitive data. By following best practices, developers can leverage UserDefaults to create seamless, persistent user experiences.

Released under the MIT License.