You can provide a handy Binding implementation that reads from & writes to the user defaults, and pass that into your Picker:
struct MyView: View {
private var value: Binding<Int> =Binding(
get: { UserDefaults.standard.integer(forKey: "Value") },
set: { UserDefaults.standard.set($0, forKey: "Value") }
)
var body: some View {
Picker("Title", selection: value) {
ForEach(0..<8) { i in
Text("Item \(i)")
}
}
}
}
For a more full-featured implementation using a property wrapper that can vend a binding directly:
@propertyWrapper
struct UserDefault<Value> {
let key: String
let defaultValue: Value
init(_ key: String, defaultValue: Value) {
self.key = key
self.defaultValue = defaultValue
}
var wrappedValue: Value {
get { Self.getWrapped(forKey: key, defaultValue: defaultValue) }
mutating set { Self.setWrapped(value: newValue, forKey: key) }
}
var projectedValue: Binding<Value> {
Binding(get: { Self.getWrapped(forKey: self.key, defaultValue: self.defaultValue) },
set: { Self.setWrapped(value: $0, forKey: self.key) })
}
static private func getWrapped(forKey key: String, defaultValue: Value) -> Value {
UserDefaults.standard.object(forKey: key) as? Value ?? defaultValue
}
static private func setWrapped(value: Value, forKey key: String) {
UserDefaults.standard.set(value, forKey: key)
}
}
struct MyView: View {
@UserDefault(key: "Value", defaultValue: 0) private var value
var body: some View {
Picker("Title", selection: $value) {
ForEach(0..<8) { Text("Item \($0)") }
}
}
}