1

I am trying to run a function after a user has selected a picker option.

The idea is that the user can set a default station, so I need to be able to send the selected value to a function so I can save it inside the core data module. How can I achieve this?

import SwiftUI

struct SettingsView: View {
    var frameworks = ["DRN1", "DRN1 Hits", "DRN1 United", "DRN1 Life"]
    @State private var selectedFrameworkIndex = 0
    
    func doSomethingWith(value: String) {
        print(value)
    }
    
    var body: some View {
        NavigationView {
            Form {
                Section {
                    Picker(selection: $selectedFrameworkIndex, label: Text("Favorite Station")) {
                        ForEach(0 ..< frameworks.count) {
                            Text(self.frameworks[$0])
                        }
                    }.onReceive([self.frameworks].publisher.first()) { value in
                        self.doSomethingWith(value: value)
                    }
                }
            }
            .navigationBarTitle("Settings")
        }
    }
}
halfer
  • 19,824
  • 17
  • 99
  • 186
RussellHarrower
  • 6,470
  • 21
  • 102
  • 204
  • Does this answer your question? [How can I run an action when a state changes?](https://stackoverflow.com/questions/56550713/how-can-i-run-an-action-when-a-state-changes) – aheze Apr 30 '21 at 03:49
  • If you want backwards compatibility, use `.onReceive(Just(selectedFrameworkIndex))` instead of `.onChange` – aheze Apr 30 '21 at 03:49

3 Answers3

0

Instead of using onRecive try using onChange.

Your code:

.onReceive([self.frameworks].publisher.first()) { value in
    self.doSomethingWith(value: value)
}

Correction:

.onChange(of: $selectedFrameworkIndex, perform: { value in
        self.doSomethingWith(value: value)
    })

this will trigger every time $selectedFrameworkIndex is changed.

a1cd
  • 17,884
  • 4
  • 8
  • 28
0

I would use a simple .onChange(of:) call on the picker. It will pick up on the change of the @State var and allow you to act on it. Use it like this:

import SwiftUI

struct SettingsView: View {
   var frameworks = ["DRN1", "DRN1 Hits", "DRN1 United", "DRN1 Life"]
   @State private var selectedFrameworkIndex = 0

    
    func doSomethingWith(value: String) {
            print(value)
      }
    
   var body: some View {
    NavigationView {
            Form {
                Section {
                    Picker(selection: $selectedFrameworkIndex, label: Text("Favorite Station")) {
                        ForEach(0 ..< frameworks.count) {
                            Text(self.frameworks[$0])
                        }
                    }
                     // Put your function call in here:
                     .onChange(of: selectedFrameworkIndex) { value in
                        print(value)
                    }

                    }
                }
            }
            .navigationBarTitle("Settings")
        }
   }


}
Yrb
  • 8,103
  • 2
  • 14
  • 44
0

yours:

import SwiftUI

struct SettingsView: View {
   var frameworks = ["DRN1", "DRN1 Hits", "DRN1 United", "DRN1 Life"]
   @State private var selectedFrameworkIndex = 0
   
   func doSomethingWith(value: String) {
       print(value)
   }
    
   var body: some View {
    NavigationView {
            Form {
                Section {
                    Picker(selection: $selectedFrameworkIndex, label: Text("Favorite Station")) {
                        ForEach(0 ..< frameworks.count) {
                            Text(self.frameworks[$0])
                        }
                    }.onReceive([self.frameworks].publisher.first()) { value in
                        self.doSomethingWith(value: value)
                    }
                }
            }
            .navigationBarTitle("Settings")
        }
   }


}

add a variable that checks to see if selectedFrameworkIndex has changed. change:

import SwiftUI

struct SettingsView: View {
    var frameworks = ["DRN1", "DRN1 Hits", "DRN1 United", "DRN1 Life"]
    @State private var selectedFrameworkIndex = 0
    @State private var savedFrameworkIndex = 0
    
   func handler<Value: Any>(val: Value) -> Value {
       if selectedFrameworkIndex != savedFrameworkIndex {
           self.doSomethingWith(value: self.frameworks[selectedFrameworkIndex])
       }
       return val
   }

    func doSomethingWith(value: String) {
        print(value)
    }
    var body: some View {
        NavigationView {
            Form {
                Section {
                    Picker(selection: handler(val: $selectedFrameworkIndex), label: Text("Favorite Station")) {
                        ForEach(0 ..< frameworks.count) {
                            Text(self.frameworks[$0])
                        }
                    }
                }
            }
            .navigationBarTitle("Settings")
        }
    }
}
a1cd
  • 17,884
  • 4
  • 8
  • 28