ChatGPT解决这个技术问题 Extra ChatGPT

What does the SwiftUI `@State` keyword do?

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.

What does the keyword mean, exactly?

How does mutating a @State variable cause the view to be recomputed?

How are other variables immutable within the body getter?

@JoakimDanielson is it a bad question?
Ok well I'm just genuinely curious about how this is implemented and what language features needed to be added.
@JoakimDanielson you can't expect nobody asks questions about new technology
@JoakimDanielson seems enough information is available already to give a pretty good answer.

f
fredpi

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.


Are they still called property delegates or is it property wrapper now? Maybe both :(
This is good info, but how does this actually work: "When the state value changes, the view invalidates its appearance and recomputes the body"? In the Integrating video the Italian guy says that SwiftUI knows that the state property is used in the body, and that it also knows which view it is in. I don't see how this is possible, do you?
@23inhouse I've added clarification about this to my post. TLDR: They mean the same, but @propertyWrapper is preferred.
@Gusutafu As a @propertyWrapper is a wrapper, it does not only know when it's written, but also when it's read – this way, it can figure out from which views it is read. I've added clarification about this to my answer.
M
Maciek Czarnik

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 that zoomed was read in body, it knows that the view's rendering depends on it. Which means - when a variable changes the framework is going to ask for body 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.


"Because SwiftUI knows that zoomed was read in body" - What mechanism in Swift makes this possible?
@Gusutafu The Combine framework (publish and subscribe). SwiftUI provides the subscriber, so it hears every time the publisher sends out a message that the variable has changed. In response, it calls body to get the interface generate afresh.
Thanks, but the thing I was struggling with was more how SwiftUI or the State itself could possibly know that the State is used in a particular body!
s
s1ro6

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.


J
Joey Slomowitz

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.


J
Josue Gisber

I like how profesor Paul Hegarty from Stanford explain it. He said that @State basically convert that variable into a pointer to some boolean somewhere else in memory and that's where the value change. But your variable - now a pointer with @State- does not change, is always pointing to that place in memory.


L
Let's_Create

Note:- The accepted answer is correct but incase you are trying to look for a easier explanation I tried below

@State property wrapper allow us to change values inside a struct.

Note:- You cannot change a property within a struct as its a values types, so its not allowed.

struct ExampleTextView: View {

    // Declare a variable with state property wrapper
    @State private var shouldChangeText: Bool = false
    
    var body: some View {
        Text("Just an example")
            .foregroundColor(Color.white)
    }
}

Incase you are wondering should we add a private access specifier? Yes, as a rule of thumb apple recommends @State propertise shouldn't be shared with other views as there are more specific property wrappers for that @ObservedObject and @EnvironmentObject.

But if it's value type how it can be mutated where is it stored then? So whenever we are marking a property with @State we move its storage out from the struct into the shared storage managed by SwiftUI.

In case in your mind if you are comparing with Swift, this is how its done there,

struct Example {
    var exampleType: String
    
    mutating func changeType() {
        exampleType = "Are we allowed to do this?"
    }
}

Credit: Please note this answer is inspired by this post https://www.hackingwithswift.com/quick-start/swiftui/what-is-the-state-property-wrapper


v
visc

If you know about C# and windows development. @State is similar if not the same as x:Bind or Binding.. On a collection it is similar if not the same as ObservableCollection.

As fredpi said, SwiftUI is listing for updates on vars with the @State property delegate.


关注公众号,不定期副业成功案例分享
Follow WeChat

Success story sharing

Want to stay one step ahead of the latest teleworks?

Subscribe Now