I have a SwiftUI (Beta 5) view with an attached ViewModel. I want to navigate to it via a navigationLink and pass in a simple parameter (called FSAC in this case)
I navigate using
NavigationLink("Next", destination: MyTestView(FSAC: "testFsac"))
The view has an FSAC Property with willSet and didSet property observer
struct MyTestView: View {
@ObservedObject var vm = MyTestViewModel()
var FSAC: String {
willSet {
print("will set fsac")
}
didSet {
print("did set fsac")
vm.FSAC = FSAC
}
}
var body: some View {
VStack {
Text("FSAC: \(FSAC)")
Text("VM FSAC: \(vm.FSAC)")
}
}
}
The print statements are never called. The first text box displays the parameter correctly; the second is blank.
How can I get the Property Observers to fire?
More generally, is there a "correct" way to use a navigationLink to pass parameters to a View that has a ViewModel?
EDIT:
On iOS 14 property observers work the same as they did in iOS 13. But, we now have the .onChange(of:perform:)
as a replacement. Docs
Text(self.myString).onChange(of: self.myString) { newValue in print("myString changed to: \(newValue)") }
Property observers on basic var
s technically work in SwiftUI. If you do something like var view = MyTestView(...)
and then view.FSAC = "updated"
the the observers will fire (I've verified this).
However, typically with SwiftUI you construct the View
(which is a struct not a class) within body
during each layout pass. In your case var body: some View { MyTestView(FSAC: "FSAC Value") }
.
Property observers do not fire during init, and therefore they aren't usually useful in SwiftUI View
s.
If you would like to update some sort of State during init, take a look at this answer.
Thanks to arsenius for an explanation as to why the Property Observers did not fire in this instance.
As a fix, I removed the property in the view, and replaced it with an init function with a signature which included the required data to be passed from the NavigationLink call. Within the init, I called a function on the ViewModel directly.
struct MyTestView: View {
@ObservedObject var vm = MyTestViewModel()
init(FSAC: String) {
if(FSAC != "") {
vm.SetFsac(FSAC: FSAC)
}
}
...
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With