Use Picker selection value outside of Picker in SwiftUI

Viewed 146

I'm a new developer who's been working with Swift & SwiftUI for a couple of months.

I have a Picker, specifically in MenuPickerStyle, that users can select before starting a timer. I want the timer to count towards whatever the user selects in the picker. How can I get the value selected from the picker and use it in logic elsewhere in my code?

I've tried to save the value of the selection parameter, but as we know SwiftUI doesn't like having logic in the View. Ideally, I'd like to get some sort of output from the Picker like you can get an output from a function so that I can use it elsewhere.

1 Answers

The fundamental solution to your question is property observers. Here is an awesome article by John to get you started..

https://www.swiftbysundell.com/articles/property-observers-in-swift/

Basically you will use a property observer to perform some logic when the value that they are observing changes. In your case, you would use a property observer on the property that you are binding your picker to.

Another way to do this that is less messy and feels more at home in SwiftUI is to add onChange() extension on the Binding type. Here's how to do that below...

extension Binding {
    func onChange(perform: @escaping (Value) -> Void) -> Binding<Value> {
        Binding(get: {
            // return wrapped value
            self.wrappedValue
        }, set: { newValue in
            // set new value
            self.wrappedValue = newValue
            // call completion
            perform(newValue)
        })
    }
    
    func onChange(perform: @escaping () -> Void) -> Binding<Value> {
        Binding(get: {
            // return wrapped value
            self.wrappedValue
        }, set: { newValue in
            // set new value
            self.wrappedValue = newValue
            // call completion
            perform()
        })
    }
}

Here is how it would be used with a picker...

Picker("Picker label", selection: $property.onChange(perform: someFunction)) {
    // values
}
Related