NEW: Learn to build the incredible iOS 15 Weather app today! >>

SOLVED: Question: why do we need @State to make var computed properties changeable while it is designed to be dynamic ?

Forums > 100 Days of SwiftUI

Hi there,

I'm working on Project 1.

When Paul introducing "state" https://www.hackingwithswift.com/books/ios-swiftui/modifying-program-state

He said

struct ContentView: View {
    var tapCount = 0

    var body: some View {
        Button("Tap Count: \(tapCount)") {
            tapCount += 1
        }
    }
}

That code looks reasonable enough: create a button that says “Tap Count” plus the number of times the button has been tapped, then add 1 to tapCount whenever the button is tapped.

However, it won’t build; that’s not valid Swift code. You see, ContentView is a struct, which might be created as a constant. If you think back to when you learned about structs, that means it’s immutable – we can’t change its values freely.

When creating struct methods that want to change properties, we need to add the mutating keyword: mutating func doSomeWork(), for example. However, Swift doesn’t let us make mutating computed properties, which means we can’t write mutating var body: some View – it just isn’t allowed.

I'm confused about why he said " we can't change cumputed properties" . I mean, var computed properties are meant to change as far as its related parameters change, right ? It is a "var", In the following case, vacationRemaining will change, given a new vacationTaken value, with or without a "@State"

struct Employee {
    let name: String
    var vacationAllocated = 14
    var vacationTaken = 0

    var vacationRemaining: Int {
        vacationAllocated - vacationTaken
    }
}

So why do we need "@State" to make computed property changeable ?

   

I mean, var computed properties are meant to change as far as its related parameters change, right ?

You are confusing two different things: 1) computed properties, and 2) the var keyword.

Computed properties are only ever read-only. In something like this:

struct Person {
    var firstName: String
    var lastName: String

    var fullName: String {
        "\(firstName) \(lastName)"
        //by the way, don't do names like this
    }
}

fullName is a computed property. It's value is determined by whatever values firstName and lastName have. You cannot set fullName, you can only read what its current value is. A computed property has to be declared with the var keyword (because its value can change depending on what is done to compute it), but that doesn't mean all vars are computed properties. In our Person struct, for instance, firstName and lastName are declared with var but they are stored properties, not computed properties. Stored properties take up memory, computed properties are, well, computed on the fly as needed.

The var keyword does usually indicate that a property is mutable.

Consider the following...

let person1 = Person(firstName: "Shelly", lastName: "Winters")
person1.firstName = "Shelby"
//error: cannot assign to property: 'person1' is a 'let' constant

var person2 = Person(firstName: "Amy", lastName: "Chilton")
person2.lastName = "Beckwith-Chilton"
//works!

Since structs are value types (meaning the value itself is stored, as opposed to reference types, which store a pointer to the value), changing a property on them actually creates a whole new instance of the struct and replaces the original. But you can't replace the value of a let constant, right? So changing the value of person1.firstName fails because person1 is declared as a let, while changing person2.lastName succeeds because person2 is declared as a var. Even though both stored properties of Person are declared as var, they still aren't necessarily mutable, depending on how the Person instance is declared.

As for the SwiftUI example, since body is a computed property, you can't use it to make changes to stored properties: it only ever computes and returns its value. Thus the need for the @State mechanism, which somehow boxes up the property value and stores it separately from the View struct (remember, structs are value types, which means the struct itself is what's stored rather than a reference to the struct), which allows us to change it as needed.

1      

@roosterboy

Thank you so much for breaking it down in details for me. Very very clear !

I have read/thought about it for the whole night, and I also went back to watch Paul's tutorial a few times.

I think I 98% understand it now... the body is a computed property... shocked me at the first place, but thenit makes every sense.

Now I have a new questions:

Are all pages we interact with on apps are "body (coumpted property)" ?

I thought it was the print() presenting the pages to users... Apprently I was too naive or too silly.

Thanks

Boat

   

print() outputs to the debug console in Xcode. It has no effect in the GUI of apps on your device.

In SwiftUI, all GUI elements are produced by the body property of a View. You declare what your Views should look like (i.e., SwiftUI is a declarative framework) by coding their body property and when the system creates a View it calls that property to construct the actual view that is displayed to the user.

If you aren't using SwiftUI, like you're using UIKit or AppKit instead, things work differently. But for SwiftUI, yes, everything comes from the computed body property.

1      

print() outputs to the debug console in Xcode. It has no effect in the GUI of apps on your device.

In SwiftUI, all GUI elements are produced by the body property of a View. You declare what your Views should look like (i.e., SwiftUI is a declarative framework) by coding their body property and when the system creates a View it calls that property to construct the actual view that is displayed to the user.

If you aren't using SwiftUI, like you're using UIKit or AppKit instead, things work differently. But for SwiftUI, yes, everything comes from the computed body property.

Can't be clearer.

Thanks @roosterboy

   

Hacking with Swift is sponsored by Sentry

SPONSORED With Sentry’s error and performance monitoring for iOS, you see mobile vitals that actually matter, can solve any latency issues quickly, and learn how each release is performing over time.

Learn More

Sponsor Hacking with Swift and reach the world's largest Swift community!

Reply to this topic…

You need to create an account or log in to reply.

All interactions here are governed by our code of conduct.

 
Unknown user

You are not logged in

Log in or create account
 

Link copied to your pasteboard.