Yes, that's the SwiftUI magic. Trust me. The framework identifies the storage location from the access pattern when constructing the view hierarchy, not the object identity. State is a struct, it doesn't even have a sense of identity.
Or do you mean that the second initial value is thrown away, then yes, the initial value is discarded in subsequent creation. You should provide the same value every time.
State is a struct that wraps a reference, and reading the wrappedValue reaches into the persistent underlying reference. When DashboardView is initialized the second time, the new value is not shoved into the persistent store; it is dropped on the floor.
Yep, and the point of what I'm trying to say is that setting @State values explicitly in an initializer breaks the expectations for how data should flow through a SwiftUI hierarchy
In all seriousness, it does have a very consistent behaviour. Though most of the time you'd want to synchronize State during view events, like onAppear instead of the view initialization. So I find the manual initialization abhorrent on almost every occasion anyway.
Any consistent behavior you see is an accident. @State's initial value must be independent of any instance of the view. Chances are good this will be enforced at compile time when the necessary property wrapper functionality exists to do so.
Even if it’s not the intended way to initialize @State, it’s the obvious approach most users will reach for and far lighter weight than creating some sort of ObservableObject as storage just to be able to set an initial value.
Is that documented anywhere? I just re-read some of the documentation and I couldn't find it called out explicitly. I can't tell you how times I've heard it recommended to initialize state that way. If that behavior is discouraged, it may be worth explicitly calling it out because, at least in the swath of the iOS community I've interacted with, that's a pretty widely accepted way of doing things.
The cases where it will appear to work are in cases where you know the view will only really be created once, e.g. in a top level of a sheet, or an “editor” view where it’ll be removed from the hierarchy after editing. If you’re relying on the fact that view won’t be re-initialized, it’s probably fine?
I’ve used this pattern in exactly these circumstances, i.e. in the top-level view in a sheet where the initial state comes from the outside, but where the state is thereafter owned and managed by the view. Why does this only ”appear to work”? What could go wrong that I’m not aware of? And what should I use instead?
wow.. just... wow. I expected to come back to a bunch of replies about.. you know.. the actual problem I posted (default init scope) and I come back to a hijacked discussion about swiftui state var behavior. Do I need to start a new post all over again? This is why swift's official github repo needs an issues section instead of this forum.
Nah you're right. Sorry for the over-the-top response. I'll dive more into the post referenced. It seems still a bit overkill for what I was after, just a basic almost C++ - like scope control over the default memberwise constructor
Btw you can generate the memberwise initializer via Xcode (right click on type > Refactor > Generate Memberwise Initializer) so you don’t have to write one out manually in this case. You can then tweak it as per your needs.
What, then, is the correct way to create a public initializer for a public view whose state variables are private and where the caller would like to specify an initial value for those variables?
Or are you saying that because they are private, the caller shouldn't know about them, the initializer shouldn't expose them, and that they should always have a default value? And if the caller really does need to know about them and supply a value that they should @Bindings instead of @State?
Multiple SwiftUI views have multiple initializers for multiple purposes. How do I create my own view that has a decent API with multiple initializers and accepts a BINDING in one case and no binding in another? I don't want to write self._binding = binding because it is obviously not an officially correct way, it is underscored.