There are multiple ways to implement persistent storage in SwiftUI, including the key property wrappers for state management.
Let me explain the key concepts demonstrated in this implementation:
import SwiftUI
import Combine
// MARK: - Data Model
class UserSettings: ObservableObject {
// @Published automatically notifies observers when value changes
@Published var username: String {
didSet {
// Save to UserDefaults whenever value changes
UserDefaults.standard.set(username, forKey: "username")
}
}
@Published var isDarkMode: Bool {
didSet {
UserDefaults.standard.set(isDarkMode, forKey: "isDarkMode")
}
}
// Initialize with stored values or defaults
init() {
self.username = UserDefaults.standard.string(forKey: "username") ?? ""
self.isDarkMode = UserDefaults.standard.bool(forKey: "isDarkMode")
}
}
// MARK: - Main App
@main
struct PersistentStorageApp: App {
// Create a single instance to be shared across the app
@StateObject private var userSettings = UserSettings()
var body: some Scene {
WindowGroup {
ContentView()
.environmentObject(userSettings)
}
}
}
// MARK: - Content View
struct ContentView: View {
// Inject the shared UserSettings instance
@EnvironmentObject var userSettings: UserSettings
var body: some View {
NavigationView {
Form {
Section(header: Text("User Settings")) {
TextField("Username", text: $userSettings.username)
Toggle("Dark Mode", isOn: $userSettings.isDarkMode)
}
Section {
NavigationLink("Profile View") {
ProfileView()
}
}
}
.navigationTitle("Settings")
}
}
}
// MARK: - Profile View
struct ProfileView: View {
@EnvironmentObject var userSettings: UserSettings
var body: some View {
VStack(spacing: 20) {
Text("Welcome, \(userSettings.username)!")
Text("Theme: \(userSettings.isDarkMode ? "Dark" : "Light")")
}
}
}
1. @ObservableObject & @Published
ObservableObject
is a protocol that allows a class to publish changes to its properties@Published
is a property wrapper that automatically notifies observers when the value changes- In our example,
UserSettings
class uses these to notify views when data changes
2. @StateObject & @EnvironmentObject
@StateObject
is used to create and maintain a single instance of an observable object@EnvironmentObject
injects shared data into views through the environment- The main app creates the
UserSettings
instance with@StateObject
- Child views access it using
@EnvironmentObject
3. Persistent Storage Implementation
- UserDefaults is used for simple persistent storage
- Changes are automatically saved when
@Published
properties are modified - Values are loaded from storage during initialization
4. Data Flow
- Changes in any view are automatically:
- Saved to UserDefaults
- Published to all observing views
- UI updates automatically reflect the changes
This implementation provides several benefits:
- Automatic persistence
- Shared state across views
- Clean separation of concerns
- Automatic UI updates
Thank you for reading!