In SwiftUI, why is a @State variable silently ignored in init()?

82 views Asked by At

Based on the order of the output in the xcode's console, it seems to suggest that default assignment happens before the execution of init(). However, the assignment in init() does not take effect. Here is the code:

TestStateVar(a_stateVar: 5)

...

struct TestStateVar: View {
    @State private var stateVar = -1
    
    init(a_stateVar: Int) {
        print("init-1: self.stateVar = \(self.stateVar)|a_stateVar = \(a_stateVar)")
        self.stateVar = a_stateVar
        print("init-2: self.stateVar = \(self.stateVar)")
    }
    
    var body: some View {
        Text("Test")
            .onAppear() {
                print("onAppear: self.stateVar = \(self.stateVar)")
            }
    }
}

Here is the output from the xcode's console:

init-1: self.stateVar = -1|a_stateVar = 5
init-2: self.stateVar = -1

onAppear: self.stateVar = -1

Is it possible, i.e., using some sort of linting, to configure xcode to detect this bug?

2

There are 2 answers

4
workingdog support Ukraine On BEST ANSWER

try using this way to initialise a @State var, such as:

init(a_stateVar: Int) {
     print("init-1: self.stateVar = \(self.stateVar) | a_stateVar = \(a_stateVar)")
     _stateVar = State(initialValue: a_stateVar) // <--- here
     print("init-2: self.stateVar = \(self.stateVar)")
 }
2
Arash Etemad On

After assigning the value of a_stateVar to self.stateVar in init, you see that it's still -1, because the @State property is not being used in the method, and the assignment is made to the local struct property, not the @State property.

You have 2 ways to fix this:

  • The answer provided by @workingdog support Ukraine
  • Remove the default of stateVar, and put it on the init argument

the second-way solution:

struct TestStateVar: View {
    @State private var stateVar: Int

    init(a_stateVar: Int = -1) {
        stateVar = a_stateVar
        print("init-2: self.stateVar = \(self.stateVar)")
    }

    var body: some View {
        Text("Test")
            .onAppear() {
                print("onAppear: self.stateVar = \(self.stateVar)")
            }
    }
}