Comportamiento extraño de wrappedValue en @State de SwiftUI
Para ir al grano, tengo este código:
struct DataModel { var option: String }
struct ViewModel { var selected: String? = "1" var options = [DataModel(option: "1"), DataModel(option: "2"), DataModel(option: "3")] }
struct ContentView: View { @State var viewModel: ViewModel
var body: some View { VStack { Picker("test", selection: aBinder()) { ForEach(viewModel.options, id: \.option) { option in Text(option.option) } } .background(Color.red) } }
func aBinder() -> Binding<string?> { Binding<string?> { viewModel.selected } set: { value in $viewModel.selected.wrappedValue = value print($viewModel.selected.wrappedValue) } } }
El valor de “selected” en el ViewModel no cambia.
Esto funciona:
struct DataModel { var option: String }
struct ViewModel { var selected: String = "1" var options = [DataModel(option: "1"), DataModel(option: "2"), DataModel(option: "3")] }
struct ContentView: View { @State var viewModel: ViewModel
var body: some View { VStack { Picker("test", selection: $viewModel.selected) { ForEach(viewModel.options, id: \.option) { option in Text(option.option) } } Button("press me", action: { print(viewModel.selected) }) } } }
Pero eso no tiene ningún sentido. En ambos casos uso una vinculación para almacenar el valor actual. ¿Qué está pasando? Soy bastante nuevo en swiftUI, así que puede que me haya perdido cómo funciona algo.
Gracias de antemano.</string?></string?>
davy.ai
El problema es con el tipo de variable
selected
en la estructuraViewModel
. En el primer fragmento de código, se declara como una cadena opcional (String?
). Sin embargo, en el segundo fragmento de código, se declara como una cadena no opcional (String
).Cuando se utiliza una vista
Picker
con una vinculación, el tipo de la variable vinculada debe coincidir con el tipo de la opciónDataModel
. Dado que la propiedadoption
enDataModel
es una cadena no opcional, la variableselected
enViewModel
también debería ser una cadena no opcional.En el primer fragmento de código, cuando se establece la variable
selected
dentro del cierre de vinculación, no se desempaqueta y el valor opcional se asigna aviewModel.selected.wrappedValue
. Esto no actualiza la variableselected
en la estructuraViewModel
.Para solucionarlo, puede cambiar el tipo de
selected
a una cadena no opcional y actualizar el cierre de vinculación para asignar el valor desempaquetado aviewModel.selected
, o puede agregar un desempaquetado explícito del valor opcional en el cierre de vinculación de la siguiente manera:La declaración
if let
verifica si el valor opcional no es nulo y lo desempaqueta antes de asignarlo aviewModel.selected
. Esto actualizará la variableselected
en la estructuraViewModel
.</string?></string?>