Home > Mobile >  Why we can't create a new instance of State in a view in SwiftUI?
Why we can't create a new instance of State in a view in SwiftUI?

Time:05-04

So in the following code:

struct ContentView: View {
@State private var blurAmount = 0.0 {
    didSet {
        print("Hey")
    }
}

init() {
    _blurAmount = State(wrappedValue: 3.3)
}
var body: some View {
    Button("Tap me") {
        
        // this line gives an error saying Cannot assign to property: 'self' is immutable
        _blurAmount = State(wrappedValue: 3.3)
    }
}

}

I know that _blurAmount is the State<Double> struct itself and _blurAmount = State(wrappedValue: 3.3) is creating a new instance of Struct. And normally would be used in init().

Expected result I wanted is it printing "Hey" whenever I tap the button. So that I can actually conform _blurAmount = State(wrappedValue: 3.3) creates a new instance of State.

But why we can't create a new instance of Struct in a View?

CodePudding user response:

This really has nothing to do with State per se. Let's take a simpler example!

struct ContentView: View {
    var greeting = "howdy"
    init() {
        greeting = "hello"
    }
    var body: some View {
        Button("Tap me") {
            greeting = "hey there" // same error
        }
    }
}

This is simply how Swift works. ContentView is a struct. A struct is not mutable in place. Thus, you can initialize greeting, but once initialization is over, you cannot modify it, because that would be a mutation of the struct ContentView, and you can't do that.

This principle is in fact one of the key principles of SwiftUI. This is exactly why @State exists; a @State variable is mutable, because it has (as you have said) a separate existence behind the scenes. The idea here is to force you to express the mutable aspects of your Views in clear and controlled manner.

Having said all that, you can assign a value to your actual variable, exactly because it is a @State variable: you can say blurAmount = 4.4 (or whatever). This is legal, and it works as you would expect:

var body: some View {
    Button("Tap me") {
        blurAmount = 4.4
    }
}
  • Related