UPGRADE YOUR SKILLS: Learn advanced Swift and SwiftUI on Hacking with Swift+! >>

'@State' used to 'keep property alive'?

Forums > SwiftUI

Dear Team,

In this video, Paul introduces us to the @Observable macro, and at 3:40 he says that @State is used in structs to 'keep the property alive' aaaanndd also watch it for changes.

This 'alive' term is a bit vague for me. 'Alive' how? I thought that 'alive' meant watching changes. So what is 'alive AND watching for changes'? In what other ways is the property 'alive' exactly?

I hope I'm not either missing something obvious or am being taken in by some semantics. This just feels very abstract to me right now. And, is this @State's 'property-alivening' feature the reason we cannot remove the @State property wrapper when we're using the @Observable macro?

Looking forward to some clarity. Thank you!

Best, Ara.

   

Hi, When a view containing a @State is created, SwiftUI also creates the object and keeps it alive as long as the view exists. This ensures the object is not destroyed and recreated with each view update, which could lead to lost state and inefficient performance. "Advanced: SwiftUI State Management". You can also read about wrapped value: State Greetings Martin

   

This 'alive' term is a bit vague for me. 'Alive' how?

🧱 Build a Lego Structure

Over the time I've been learning SwiftUI, I've come to think of a view as a small box of Lego pieces with instructions. If I am a view builder, hundreds of times each second the application hands me a small box of Lego and am told to build what's in the box. The old structure is tossed into the rubbish bin 🗑️ never to be seen again. I build the new structure from the pieces in the new box I'm given. I am very busy building views!!

So imagine I give you a box of multicolored lego bricks 🧱with the instructions to construct five rows, each containing four bricks. Each time I hand you a box with 20 random Lego bricks, you assemble a randomly colored structure. Sweet!

The previous state of the structure dies when you're directed to assemble a new structure.

Keep the First Row the Same

But now consider a set of instructions that tell you to save the color configuration of the first row of the previous structure then build the rest of the structure with random bricks.

How do you keep the state of the first row alive between the 1000s of structures that you're building? You might consider writing the color sequence on a scrap of paper? Then when you get a new box of lego pieces, you consult the scrap of paper, assemble the first row per the state that is saved on the paper, then build the rest of the structure with random bricks.

In short, this is how @State variables keep data alive. The variable is written to a chunk of memory outside of the struct. Each time the struct is rebuild in SwiftUI, the application builds the view per its instructions, but consults the external chunk of memory for the @State variable. Thus, it stays alive between rebuilds.

You receive a box of Lego pieces with instructions inside on how to build a structure. But now one of the instructions says to consult the PostIt note outside the box for instructions for building just the first row.

Please consider that a simple view in SwiftUI may be destroyed and rebuilt thousands of times a second as animation, or data on the screen is updated!

Here's a Brick Example

Here's some sample code illustrating this concept.

struct BoxOfBricksView: View {
    // ========= PARTS FOR BUILDING ================
    @State private var redrawThisView  = false

    // this is an array of random colored bricks.
    // but the state is saved when the view is destroyed then redrawn
    @State private var savedRowOfBricks = [Brick]()

    // this is also an array of random color bricks
    // this is random each time this view is drawn
    var randomRowOfBricks: [Brick] {
        if redrawThisView { [Brick(), Brick(), Brick(), Brick() ] }
        else {              [Brick(), Brick(), Brick(), Brick() ] }
    }
    // ========= ASSEMBLY INSTRUCTIONS ================
    var body: some View {
        VStack {
            // The state of this row of bricks is saved between redraws
            BrickRow(builtUsing: savedRowOfBricks )
            // These rows are random each time. State is NOT saved.
            BrickRow(builtUsing: randomRowOfBricks)
            BrickRow(builtUsing: randomRowOfBricks)
            BrickRow(builtUsing: randomRowOfBricks)
            BrickRow(builtUsing: randomRowOfBricks)
            // ------------- force a redraw ---------
            Button("Redraw", systemImage: "pencil") { redrawThisView.toggle() }
                .buttonStyle(.borderedProminent).padding(.vertical)
        }
        // Generate random colored bricks for the first row
        .onAppear { savedRowOfBricks = randomRowOfBricks }
        .animation(.easeIn, value: redrawThisView)
    }
}

// Each time you create a brick you get a random color
struct Brick: Identifiable {
    var id         = UUID().uuidString // satisfy the ForEach view builder
    let brickColor = [Color.blue, .red, .purple, .indigo, .mint, .yellow].randomElement()!
}

// draw a single brick
struct BrickView: View {
    let withColor: Color  // <-- Draw a brick with this color
    var body:      some View {
        Rectangle()
            .foregroundColor(withColor)
            .frame(width: 80, height: 35).cornerRadius(7.0)
    }
}

// Draw a row of bricks.
struct BrickRow: View {
    // ===== PARTS =======
    private var rowOffset: CGFloat { [-20, 20, 10, -5, 15, -30, 0].randomElement()! }
    let builtUsing: [Brick]  // <-- Pass in an array of bricks
    // ===== INSTRUCTIONS =====
    var body:   some View {
        HStack(spacing: 4) {
            ForEach(builtUsing) { brick in
                BrickView(withColor: brick.brickColor)
            }
        }.offset(x: rowOffset )
    }
}

Keep Coding

1      

Hacking with Swift is sponsored by RevenueCat.

SPONSORED Take the pain out of configuring and testing your paywalls. RevenueCat's Paywalls allow you to remotely configure your entire paywall view without any code changes or app updates.

Click to save your free spot now

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.