No description
Find a file
2026-04-03 10:25:18 -07:00
.swiftpm/xcode/package.xcworkspace/xcshareddata Initial Commit 2023-09-05 15:27:54 +07:00
Sources Updated to latest swift-syntax package. 2024-07-08 17:52:43 +01:00
Tests/ObservableUserDefaultTests Added support for all types, including arrays and dictionaries. 2023-12-20 22:17:53 +00:00
.gitignore Initial Commit 2023-09-05 15:27:54 +07:00
LICENSE Initial commit 2023-09-05 15:17:29 +07:00
Package.resolved Change swift-syntax to version 602 2026-04-03 10:25:18 -07:00
Package.swift Change swift-syntax to version 602 2026-04-03 10:25:18 -07:00
README.md Added support for optional types. 2023-09-19 01:01:03 +07:00

ObservableUserDefault

ObservableUserDefault is an attached Swift macro for properties in @Observable classes that provides accessor blocks with getters and setters that read and write the properties in UserDefaults.

Usage

Note that the @ObservationIgnored annotation is necessary when using @ObservableUserDefault owing to the way that @Observable works: Without it, the @Observable macro will inject its own getters and setters in the accessor block and the macros will conflict, causing errors.

import ObservableUserDefault

@Observable
final class StorageModel {
    @ObservableUserDefault
    @ObservationIgnored
    var name: String
}

This will automatically generate the following code:

@Observable
final class StorageModel {
    @ObservationIgnored
    var name: String {
        get {
            access(keyPath: \.name)
            return UserDefaults.name
        }
        set {
            withMutation(keyPath: \.name) {
                UserDefaults.name = newValue
            }
        }
    }
}

Arguments can be provided to the macro for cases when you want to provide UserDefaults storage keys, default values, and suites explicitly. When attached to non-optional types, default values must be included in the arguments.

import ObservableUserDefault

@Observable
final class StorageModel {
    @ObservableUserDefault(.init(key: "NAME_STORAGE_KEY", defaultValue: "John Appleseed", store: .standard))
    @ObservationIgnored
    var name: String
}

This will automatically generate the following code:

@Observable
final class StorageModel {
    @ObservationIgnored
    var name: String {
        get {
            access(keyPath: \.name)
            return UserDefaults.standard.value(forKey: "NAME_STORAGE_KEY") as? String ?? "John Appleseed"
        }
        set {
            withMutation(keyPath: \.name) {
                UserDefaults.standard.set(newValue, forKey: "NAME_STORAGE_KEY")
            }
        }
    }
}

When attached to optional types, omit the default value from the argument.

import ObservableUserDefault

@Observable
final class StorageModel {
    @ObservableUserDefault(.init(key: "NAME_STORAGE_KEY", store: .standard))
    @ObservationIgnored
    var name: String?
}

This will automatically generate the following code:

@Observable
final class StorageModel {
    @ObservationIgnored
    var name: String? {
        get {
            access(keyPath: \.name)
            return UserDefaults.standard.value(forKey: "NAME_STORAGE_KEY") as? String
        }
        set {
            withMutation(keyPath: \.name) {
                UserDefaults.standard.set(newValue, forKey: "NAME_STORAGE_KEY")
            }
        }
    }
}

Installation

The package can be installed using Swift Package Manager. To add ObservableUserDefault to your Xcode project, select File > Add Package Dependancies... and search for the repository URL: https://github.com/davidsteppenbeck/ObservableUserDefault.git.

License

ObservableUserDefault is available under the MIT license. See the LICENSE file for more info.