Expressions are not allowed at the top level.
To test your case I created a View struct called Test1, and within its initialiser I created object for Test view. Check code below.
import SwiftUI
struct Test1:View {
init() {
let test = Test() // concentrate on this
test.countUp()
}
var body: some View {
Test() // Ignore for now
}
}
Test View-:
import SwiftUI
@propertyWrapper struct TestCount:DynamicProperty {
@State private var count = 0
var wrappedValue: Int {
get {
count
}
nonmutating set {
count = newValue
}
}
init(_ count: Int) {
self.count = count
}
}
struct Test: View {
@TestCount var count:Int
init(count:Int) {
_count = TestCount(count)
print(_count)
}
var body: some View {
Button {
countUp()
} label: {
Text("\(count)")
}
}
func countUp() {
count += 1
print(count)
}
}
For better understanding I created a custom propertyWrapper and we will initialise that inside Test view.
Now, when you run this code in simulator Test1 view is called first, and in it’s initialiser it will create object for Test() view.
Test view upon initialisation will create object for it’s property wrapper called TestCount, once created it will print description for TestCount instance, and notice the print output now-:
TestCount(_count: SwiftUI.State<Swift.Int>(_value: 0, _location: nil))
You can clearly see State variable count inside TestCount wrapper was assigned default value 0, but wasn’t allocated any SwiftUI.StoredLocation yet.
Now, this line is executed next test.countUp() in Test1 view, and because we are calling it from outside of body property and Test1 is also initialised outside of body property , compiler is smart enough to detect that and it will not provide SwiftUI storage location for this change to count variable, because there is no view update required for this change, hence you always see Output as 0 (default saved value).
To prove my point, now make following change in Test1 view.
import SwiftUI
struct Test1:View {
// init() {
// let test = Test(count: 0)
// test.countUp() // I want "count" property to be count up. but it did not
// }
var body: some View {
Test(count: 0)
}
}
Now again the initial print statement inside Test view is same -:
TestCount(_count: SwiftUI.State<Swift.Int>(_value: 0, _location: nil))
But, now you have a view with Button to change the count variable value on tap.
When you tap the button, again countUp() will be called, and this time check the output of print statement again, SwiftUI storage location is no more nil.
TestCount(_count: SwiftUI.State<Swift.Int>(_value: 0, _location:
Optional(SwiftUI.StoredLocation<Swift.Int>))).
You can debug the code further to get more better understanding, and I would also suggest you to read about PropertyWrappers in more detail, and how they work internally.
Expressions are not allowed at the top level, so how does that work at all? That being said, you can't access@Stateproperties from outside thestructlike that. You'll probably need to look into the@Publishedproperty wrapper.