The SwiftUI tutorial uses the @State
keyword to indicate mutable UI state:
@State var showFavoritesOnly = false
It offers this summary:
State is a value, or a set of values, that can change over time, and that affects a view’s behavior, content, or layout. You use a property with the @State attribute to add state to a view.
@State
variable cause the view to be recomputed?body
getter?SwiftUI provides property wrappers and other tools to create and modify the single source of truth for values and for objects: User interface values: Use @State and @Binding for values like showAddThing that affect the view's appearance. The underlying type must be a value type like Bool , Int , String or Thing .
SwiftUI uses the @State property wrapper to allow us to modify values inside a struct, which would normally not be allowed because structs are value types. When we put @State before a property, we effectively move its storage out from our struct and into shared storage managed by SwiftUI.
@State property wrappers are used to read and write variables from a structure. It is used in single view and is recommended that you set its property as private so that other views cannot access it. @Binding property wrappers are used to access variables from other views.
SwiftUI manages the storage of a property that you declare as state. When the value changes, SwiftUI updates the parts of the view hierarchy that depend on the value. Use state as the single source of truth for a given value stored in a view hierarchy.
The @State
keyword is a @propertyWrapper
, a feature just recently introduced in Swift 5.1. As explained in the corresponding proposal, it's sort of a value wrapper avoiding boilerplate code.
Sidenote: @propertyWrapper
has previously been called @propertyDelegate
, but that has changed since. See this post for more information.
The official @State documentation has the following to say:
SwiftUI
manages the storage of any property you declare as a state. When the state value changes, the view invalidates its appearance and recomputes the body. Use the state as the single source of truth for a given view.A State instance isn’t the value itself; it’s a means of reading and mutating the value. To access a state’s underlying value, use its value property.
So when you initialize a property that's marked @State
, you're not actually creating your own variable, but rather prompting SwiftUI
to create "something" in the background that stores what you set and monitors it from now on! Your @State var
just acts as a delegate to access this wrapper.
Every time your @State
variable is written, SwiftUI
will know as it is monitoring it. It will also know whether the @State
variable was read from the View
's body
. Using this information, it will be able to recompute any View
having referenced a @State
variable in its body
after a change to this variable.
Its explained nicely with an example in the WWDC video - Session 204 (starts at 16:00, quotation starts at 20:15)
One of the special properties of
@State
variables is that SwiftUI can observe when they're read and written. Because SwiftUI knows thatzoomed
was read inbody
, it knows that the view's rendering depends on it. Which means - when a variable changes the framework is going to ask forbody
again using the new@State
value.
The @State
as a Property Wrapper is also elaborated and justified in Data Flow Through Swift UI (5:38) WWDC vid as well. It's shown how it solves the problem when we need a mutable value in an immutable (struct
) View
.
Let me add something else if you know React Native.
The @State
property is very like the this.state
object in React Native.
For example:
struct Foobar: some View {
@State var username = ""
}
class Foobar extends React.Component {
constructor(props) {
super(props);
this.state = {
username: '',
};
}
}
When you modify the username variable, they will have the same effect, that re-render the current page.
If you click into @State
you can see that it has several getters. One with Value
another with Binding<Value>
.
SwiftUI seems to rely heavily on reactive programming (and their new Combine
framework, and since we cannot see the full implementation of these wrappers, I would expect that the values that are stored through @State
property wrappers are being managed by a CurrentValueSubject
from Combine
. Like the name implies, this essentially stores the current value, which can then be used as a bindable property by using the $
syntax.
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