SwiftUI Preset Picker

When I create a picker, for example font settings, it always show the values, but not with the last selected one preselected. How can I create a picker that has the last selected value shown selected the next time the view is viewed. I plan to store the last selected value in UserDefaults.


Thank in advance for any help.

Here is an example for a datePicker


struct ContentView: View {
    var dateFormatter: DateFormatter {
        let formatter = DateFormatter()
        formatter.dateStyle = .long
        return formatter
    }

    @State private var birthDate = Date().addingTimeInterval(-86400*365)

    var body: some View {
        VStack {
            Text("Select a date")
            DatePicker(selection: $birthDate, in: ...Date(), displayedComponents: .date) {
                Text("date")
            }

            Text("Birth date is \(birthDate, formatter: dateFormatter)")
        }.labelsHidden()    // Hide the left label
    }
}


if you compute birthDate (reading from UserDefaults for instance) instead of setting it, you open on selected date.

Or for a basic Picker


    @State private var selection = 2     // set with user defaults
 
    var body: some View {
        VStack {
 
            Picker("Pick", selection: self.$selection) {
                ForEach(0..<10) { i in
                    Text("Item \(i)")
                }
          }
     }

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)") }
        }
    }
}
SwiftUI Preset Picker
 
 
Q