SwiftUI Picker.onchange not changing.

The incoming vm data sets the Picker as expected, but .onchange is NOT executing. Is this another Apple bug or am I doing this wrong?

import Foundation

import SwiftUI



struct ExamplePicker: View {

    @EnvironmentObject var vm: ViewModel

    

    let availableSymbolRates = [

        /* band 0 */ ["-","AUTO","1500"],

        /* band 1 */ ["-","AUTO","25","33","66","125"],

        /* band 2 */ ["-","AUTO","250","333","500"],

        /* band 3 */ ["-","AUTO","1000","1500"]

    ]

    

    var body: some View {

        HStack {

            Text("Symbol Rate")

            Spacer()

            Picker("", selection: $vm.response.RxSymbolRate) {

                ForEach(availableSymbolRates[vm.response.RxBand], id: \.self) {

                    Text($0)

                }

            }

            .onChange(of: vm.response.RxSymbolRate, perform: { value in

                print("Rx Symbol Rate changed to: \(value)")

                vm.request(action: .RXSR, param: value)

            })

        }

    }

}

The double line spacing is a forum bug.

Answered by EA7K in 686818022

This is the most ridiculous solution I've ever come up with, but it works.

Spacer().onchange - really?

Please could someone from Apple, or anyone, show me a more elegant way.

		HStack {
			Text("Symbol Rate")
			Spacer().onChange(of: vm.response.RxSymbolRate, perform: { value in
				symbolRateSTATE = vm.response.RxSymbolRate
			})
			Picker("", selection: $symbolRateSTATE) {
				ForEach(vm.response.RxSymbolRateArray, id: \.self) {
					Text($0)
				}
			}
			.onChange(of: symbolRateSTATE, perform: { newState in
				vm.request(action: .RXSR, param: newState)
			})
			.onChange(of: vm.response.RxSymbolRate, perform: { newState in
				symbolRateSTATE = newState
			})
		}

The double line spacing is a forum bug.

Have you tried Paste and Match Style?


am I doing this wrong?

I guess you are doing something wrong. As far as I tried your code (I needed to fill many parts by guess, though), I could get Rx Symbol Rate changed to: ... in the console.

Can you show enough code to reproduce the issue? I guess your ViewModel is sort of broken.

Can you show enough code to reproduce the issue? I guess your ViewModel is sort of broken.

I'd love to know what parts you guessed, because I've wondering about the ViewModel too. In fact, I've always been confused on where things need to initialised. Logic tell me the the ViewModel (source of truth) should be first, but that's impossible these days. I have...

@main
struct Sat_ControllerApp: App {
    @StateObject var vm = ViewModel()
    var body: some Scene {
        WindowGroup {
            ContentView().environmentObject(vm)
        }
    }
}

and in ViewModel...

final class ViewModel: ObservableObject, ActiveDelegate {
    @Published var response = ServerStatusAPI()

The ActiveDelegate protocol is used in a NetworkService class.

I should also mention UI has hundreds of memory leaks. Perhaps I should be using Combine, if only I could understand it.

Thank you for your help.

Accepted Answer

This is the most ridiculous solution I've ever come up with, but it works.

Spacer().onchange - really?

Please could someone from Apple, or anyone, show me a more elegant way.

		HStack {
			Text("Symbol Rate")
			Spacer().onChange(of: vm.response.RxSymbolRate, perform: { value in
				symbolRateSTATE = vm.response.RxSymbolRate
			})
			Picker("", selection: $symbolRateSTATE) {
				ForEach(vm.response.RxSymbolRateArray, id: \.self) {
					Text($0)
				}
			}
			.onChange(of: symbolRateSTATE, perform: { newState in
				vm.request(action: .RXSR, param: newState)
			})
			.onChange(of: vm.response.RxSymbolRate, perform: { newState in
				symbolRateSTATE = newState
			})
		}
SwiftUI Picker.onchange not changing.
 
 
Q