In SwiftUI we can use @AppStorage
to save app settings. In my app, I have a settings view which allows the user to change various settings. Since there are many of them, it's not practical to declare a binding for each setting between the settings view and whatever other views effectively use that setting.
Is there a more convenient way to store a setting in one view and access it in another view?
I'll add to @Claude31 suggestions,
Since @AppStorage reflects values from UserDefaults and User Defaults supports types such as Data, Arrays, Dictionaries which might be more appropriate.
Using binary data as your type allows you store and manage multiple settings in a single Settings struct. For example:
struct Settings: Codable {
var isLoggedIn: Bool
var isActive: Bool
...
}
You could easily convert to and from binary data:
struct Settings: Codable {
var isLoggedIn: Bool
var isActive: Bool
func toBinaryData() -> Data? {
let encoder = JSONEncoder()
do {
let data = try encoder.encode(self)
return data
} catch {
print("Failed to encode Settings to binary data: \(error)")
return nil
}
}
static func fromBinaryData(_ data: Data) -> Settings? {
let decoder = JSONDecoder()
do {
let settings = try decoder.decode(Settings.self, from: data)
return settings
} catch {
print("Failed to decode binary data to Settings: \(error)")
return nil
}
}
}
You could then convertSettings
struct to binary data when the scenePhase changes or if the value changes:
struct ContentView: View {
@AppStorage("Keyvalue") var settingsBinaryData: Data?
@State private var appSettings: Settings = Settings(isLoggedIn: false, isActive: true)
@Environment(\.scenePhase) private var scenePhase
var body: some View {
VStack {
Toggle(isOn: $appSettings.isLoggedIn) {
Text("Is Logged In")
}
.padding()
Toggle(isOn: $appSettings.isActive) {
Text("User is active")
}
.padding()
}
.onChange(of: scenePhase) { _, phase in
if phase == .inactive {
if let settingsData = appSettings.toBinaryData() {
settingsBinaryData = settingsData
}
} else if phase == .active {
if let binaryData = settingsBinaryData, let settings = Settings.fromBinaryData(binaryData) {
appSettings = settings
}
}
}
}
}
Keep in mind that UserDefaults isn't suitable for storing large data, so you might want to consider alternatives such as: File Storage or Core Data.