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.
Are you sure about that? I never even considered using anything like that. I would guess most people are like me and are too wary of SwiftUI magic to use things in a radically different way from official recommendations.
My point was that there is no official recommendation or anything preventing the use of the initializer like that, so that's what most users will reach for by default. Apple has no obvious examples of initializing a View with initial @State values so unless they do their own research there's no way for them to figure out that @State in SwiftUI is different than other wrappers you might want to initialize.
That obviously not what we're talking about here. The question is, how do you provide an initial value to that state from outside the view? Naturally users would reach for the initializer, but that's apparently not what you're supposed to do. That realization is both non obvious and not really documented.
My impression was that you're not supposed to use it like that, that State properties should only be used internally and if you want to pass in data you use a normal let property, or a Binding if you want to change it.
I guess this doesn't really cover the case where you want to get a starting value from the outside, but don't want to bother the outside with any subsequent changes to the value, but for me it would still be more natural to use a binding then. Or simply update the State properties value in the initialiser based on the input (does that work?)
That can work, if the views are directly related. But you still have the non-obvious nature of binding state you don't care about in the parent view. However, once there's more than a single layer between the state and the source of the initial value, it gets especially burdensome to constantly bind and rebind. For instance, I want to provide an initial value to a Picker based on the button that was tapped to navigate to the screen where the Picker is a child view. Outside of the Picker I don't care what the selection is, I just want to provide an initial value. It seems natural to reach for an initializer to provide this value, rather than having to set up a Binding or ObservableObject for that sole purpose.
Hm, but wouldn't you normally want to use the picker value somewhere? Isn't the beauty of SwiftUI that you can keep everything in sync all the time, automatically. In such cases I would have a sort of Coordinator as an environment object with a property that you bind directly to the picker.
Perhaps in this case the initial value is separate from the picked value? If so, can't you just pass it in through a var/let property, since you are not going to change it?