Home > Mobile >  Why won't this simple @State (SwiftUI on MacOS) example update the View?
Why won't this simple @State (SwiftUI on MacOS) example update the View?

Time:11-30

Xcode 14.1 (14B47b), Ventura 13.0.1, Swift 5

When clicking the button, it prints consecutive numbers in the debug window, but the SwiftUI View does not update. I couldn't get it to work on a much more complicated app and ran into this problem. Then I reduced it to this test project, and it still dosn't work.

This should be a trivial use of @State. This is for a SwiftUI app running on MacOS.

What am I doing wrong (other than losing my mind)?

import SwiftUI

var globalCounter:Int = 0

@main
struct State_TestApp: App {
    init() {
        globalCounter = 1
    }
    var body: some Scene {
        WindowGroup {
            ContentView(counter:globalCounter)
        }
    }
}

func addOne()  {
    globalCounter  = 1
    print(globalCounter)
}

struct ContentView: View {
    
    @State var counter:Int
    
    var body: some View {
        VStack {
            Button("Add one") {
                addOne()
            }
            Text("\(counter)")
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView(counter:globalCounter)
    }
}

CodePudding user response:

Because a global variable cannot trigger View updates and because counter isn't being updated, @State var counter:Int is a source of truth that is being initialized with the value from globalCounter there is no connection between them.

always declare state as private, and place it in the highest view in the view hierarchy that needs access to the value.

Use state as the single source of truth for a given value stored in a view hierarchy.

https://developer.apple.com/documentation/swiftui/state

CodePudding user response:

Here is the answer for those that want to do something similar.


@main
struct State_TestApp: App {

    var body: some Scene {
        WindowGroup {
            ContentView(start:3)
        }
    }
}

func addOne(number:Int) -> Int {
    return number   1
}

struct ContentView: View {
    
    init(start:Int) {
        counter = start
    }
    
    @State private var counter:Int
    
    var body: some View {
        VStack {
            Button("Add one") {
                counter = addOne(number: counter)
            }
            Text("\(counter)")
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView(start:4)
    }
}
  • Related