WLStorage is a thread-safe, Codable-backed property wrapper for persistent local key-value storage in Swift. It keeps Codable values cached in memory and persists changes through a configurable storage backer.
Add WLStorage to your project via Swift Package Manager by specifying the package repository URL:
https://github.com/wegenerlabs/WLStorage.git
Declare a property with the @WLStorage wrapper by providing a unique key and a default value:
@WLStorage(key: "first_name", defaultValue: nil)
var firstName: String?WLStorage is observable and compatible with SwiftUI:
private struct MyView: View {
@EnvironmentObject var storage: WLStorage<String>
var body: some View {
TextField("Label", text: $storage.wrappedValue)
}
}- During initialization,
WLStorageattempts to load the value from its backer. - If no value exists, the default is saved and used.
- Updates to the property are cached immediately and persisted asynchronously by default.
- Persistence is throttled to once per second by default. Pass
flushInterval: nilto disable throttled automatic flushing and callflush()manually. - Data is flushed automatically on
deinitand on app termination or backgrounding. - The default backer stores files in the app's Documents directory under
.wlstorage(or.wlstorage_debugin debug builds). - The default backer writes atomically and stores unsafe file names as SHA-256 hashes.
- Memory access is serialized on a private queue, and disk writes are serialized on a separate private queue.
- SwiftUI change notifications are delivered on the main thread.
Use WLStorageBacker to provide custom persistence:
let storage = WLStorage(
defaultValueClosure: { UserSettings() },
backer: MyStorageBacker(key: "settings")
)WLStorageDefaultBacker can also be initialized with a custom directory:
let backer = WLStorageDefaultBacker<UserSettings>(
key: "settings",
directory: cacheDirectory
)Backer writes for a single WLStorage instance are serialized by WLStorage on a private background queue. Avoid sharing one backer instance across multiple WLStorage instances unless the backer handles its own synchronization.
- Calls
assertionFailureif the default storage directory URL is unavailable. - Calls
assertionFailureif JSON decoding or encoding fails. - Calls
assertionFailureif disk I/O fails. - Missing or empty files use the default value.
init(key: String, defaultValue: T)or
init(key: String, defaultValueClosure: () -> T)or
init(defaultValueClosure: () -> T, flushInterval: Int? = 1, backer: any WLStorageBacker<T>)key: String— The storage key.wrappedValue: T— The cached value.
flush()— Forces a synchronous write of the latest pending value.
Code should be formatted with swiftformat (default settings):
brew install swiftformat
swiftformat .MIT License