SwiftUI Documentation for #State property wrapper - swift

I recently ran into an issue where I had to init an #State variable in my init method. This post helped me figure that out.
What I realized was that this is the way to do it:
#State var fullText: String // No default value of ""
init(letter: String) {
_fullText = State(initialValue: list[letter]!)
}
I understand that #State is a property wrapper, and I read the documentation on property wrappers. And from other reading I discovered under the hood this code:
#State private var flag = false
is translated into this code:
private var _flag: State<Bool> = State(initialValue: false)
private var $flag: Binding<Bool> { return _flag.projectedValue }
private var flag: Bool {
get { return _flag.wrappedValue }
nonmutating set { _flag.wrappedValue = newValue }
}
My question is where is it documented that _variableName is created from the wrapped property method and I can redefine it? How is a SwiftUI developer supposed to know that from Apple's docs? I'm trying to find what I'm assuming is Documentation I'm missing.

As property wrappers were a Swift Evolution proposal and were developed as part of Swift's open source philosophy, we can find the best documentation directly in the Proposal SE-0258 document.
This describes the rationale behind the #propertyWrapper design, and the exact specification to how they are implemented (including the definitions of wrapped values and projected values).
Sections that may help in your understanding:
§ A property wrapper type provides the storage for a property that uses it as a wrapper. The wrappedValue property of the wrapper type provides the actual implementation of the wrapper, while the (optional) init(wrappedValue:) enables initialization of the storage from a value of the property's type.
The use of the prefix _ for the synthesized storage property name is deliberate: it provides a predictable name for the synthesized storage property that fits established conventions for private stored properties.
[...]
§ A property wrapper type can choose to provide a projection property (e.g., $foo) to expose more API for each wrapped property by defining a projectedValue property.
As with the wrappedValue property and init(wrappedValue:), the projectedValue property must have the same access level as its property wrapper type.
As property wrappers are new to Swift as a whole, documentation is still lacking on Apple's side in my opinion, especially when it comes to SwiftUI.
However, there are only a handful of property wrappers we really have to know about (#State, #Binding, #EnvironmentObject, #ObservedObject, #Published) to fully utilise SwiftUI; all other aspects of SwiftUI (such as View types) are pretty well documented in Apple's Developer docs.
Additionally, articles shared in the Swift community (example) can help you to get a grasp on where you might want to implement property wrappers yourself!

Related

SwiftUI Textfield: Meaning of the $ in front of a State-variable? [duplicate]

This tutorial by Apple about SwiftUI uses a dollar sign to bind data, and I‘m having trouble finding more information about this data binding in SwiftUI.
Toggle(isOn: $showFavoritesOnly) {
You use the $ prefix to access a binding to a state variable, or one of its properties.
Is this some sort of inout type parameter? That uses the ampersand to pass it on.
This is very well explained in WWDC 2019 video 415. You are merely looking at one special case of a broad language feature, namely property wrappers.
A property wrapper (such as #State) is actually a way of referring to an instance of a type (usually a struct or enum) with the same name (such as State). The latter provides instructions for turning this instance property into a computed property whose getter and setter are the getter and setter for a certain computed property of itself (its wrappedValue). It also typically holds private storage backing that computed property.
Thus, after the declaration
#State var showFavoritesOnly = true
...showFavoritesOnly is turned into a computed property, with its getter and setter supplied by the State struct. When you set showFavoritesOnly to true, that is routed through the State struct's setter and ends up in a stored property of the State instance.
All of this implies that somewhere there is a State instance associated with your showFavoritesOnly. And there is, but it's hidden from view. Its name, in case you'd like to see that State instance, is _showFavoritesOnly.
Okay, but when you say $showFavoritesOnly, you do not get a State struct; you get a Binding struct. Why? That's because a property wrapper has a mechanism for specifying what the returned value from the $ name should be. In the case of State, it specifies that this value should be its own binding property, which is a Binding (see the docs: https://developer.apple.com/documentation/swiftui/state).
By an amazing coincidence, Toggle's isOn initializer takes a Binding (again, see the docs, https://developer.apple.com/documentation/swiftui/toggle/3232112-init). You could not have set the Toggle's isOn to showFavoritesOnly even if you wanted to! Instead, you set it to the Binding<Bool> supplied by the State instance, so that the Toggle has automatic two-way communication with the State object. The SwiftUI framework enforces its own correct usage; a Toggle can exist only in relation to some binding that acts as the underlying source of truth for its on/off state. And because it's a binding, not a mere Bool, communication works in both directions: when the user taps the switch in the Toggle, the change in value flows "up" to the State variable by way of the binding.
The $ is used in conjunction with property wrappers (previously known as "property delegates").
It's not an operator, but a prefix (thanks #matt!).
For more about property delegates, see this Swift Evolution document.
e.g. in #State var aState = false, State is a property wrapper.
This means that if we write:
aState we're accessing a Bool value
$aState we're accessing a Binding<Bool> value
Different property delegates will generate different values, called "projected values".

#State autogenerated underscore-prefixed member variable

I noticed via an Xcode autocompletion suggestion that #State seems to not only autogenerate a $-prefixed member for accessing the corresponding Binding (as is commonly known), but also a _-prefixed member, seemingly exposing the actual State wrapper.
This makes me wonder, what's the use case for it, and where is it mentioned in the docs?
I found out it's actually due to how Swift (rather than SwiftUI) compiles propertyWrappers under the hood.
From the official swift docs (under propertyWrapper):
The compiler synthesizes storage for the instance of the wrapper type by prefixing the name of the wrapped property with an underscore (_)—for example, the wrapper for someProperty is stored as _someProperty. The synthesized storage for the wrapper has an access control level of private.
Here's what's happening each time you use a propertyWrapper:
(From better programming)
As to its practical application in the context of SwiftUI, you can use it to initialize the #State variable, as described in this SO answer or this blog post.

What does the dollar sign do in Swift / SwiftUI?

This tutorial by Apple about SwiftUI uses a dollar sign to bind data, and I‘m having trouble finding more information about this data binding in SwiftUI.
Toggle(isOn: $showFavoritesOnly) {
You use the $ prefix to access a binding to a state variable, or one of its properties.
Is this some sort of inout type parameter? That uses the ampersand to pass it on.
This is very well explained in WWDC 2019 video 415. You are merely looking at one special case of a broad language feature, namely property wrappers.
A property wrapper (such as #State) is actually a way of referring to an instance of a type (usually a struct or enum) with the same name (such as State). The latter provides instructions for turning this instance property into a computed property whose getter and setter are the getter and setter for a certain computed property of itself (its wrappedValue). It also typically holds private storage backing that computed property.
Thus, after the declaration
#State var showFavoritesOnly = true
...showFavoritesOnly is turned into a computed property, with its getter and setter supplied by the State struct. When you set showFavoritesOnly to true, that is routed through the State struct's setter and ends up in a stored property of the State instance.
All of this implies that somewhere there is a State instance associated with your showFavoritesOnly. And there is, but it's hidden from view. Its name, in case you'd like to see that State instance, is _showFavoritesOnly.
Okay, but when you say $showFavoritesOnly, you do not get a State struct; you get a Binding struct. Why? That's because a property wrapper has a mechanism for specifying what the returned value from the $ name should be. In the case of State, it specifies that this value should be its own binding property, which is a Binding (see the docs: https://developer.apple.com/documentation/swiftui/state).
By an amazing coincidence, Toggle's isOn initializer takes a Binding (again, see the docs, https://developer.apple.com/documentation/swiftui/toggle/3232112-init). You could not have set the Toggle's isOn to showFavoritesOnly even if you wanted to! Instead, you set it to the Binding<Bool> supplied by the State instance, so that the Toggle has automatic two-way communication with the State object. The SwiftUI framework enforces its own correct usage; a Toggle can exist only in relation to some binding that acts as the underlying source of truth for its on/off state. And because it's a binding, not a mere Bool, communication works in both directions: when the user taps the switch in the Toggle, the change in value flows "up" to the State variable by way of the binding.
The $ is used in conjunction with property wrappers (previously known as "property delegates").
It's not an operator, but a prefix (thanks #matt!).
For more about property delegates, see this Swift Evolution document.
e.g. in #State var aState = false, State is a property wrapper.
This means that if we write:
aState we're accessing a Bool value
$aState we're accessing a Binding<Bool> value
Different property delegates will generate different values, called "projected values".

What does the SwiftUI `#State` keyword do?

The SwiftUI tutorial uses the #State keyword to indicate mutable UI state:
#State var showFavoritesOnly = false
It offers this summary:
State is a value, or a set of values, that can change over time, and that affects a view’s behavior, content, or layout. You use a property with the #State attribute to add state to a view.
What does the keyword mean, exactly?
How does mutating a #State variable cause the view to be recomputed?
How are other variables immutable within the body getter?
The #State keyword is a #propertyWrapper, a feature just recently introduced in Swift 5.1. As explained in the corresponding proposal, it's sort of a value wrapper avoiding boilerplate code.
Sidenote: #propertyWrapper has previously been called #propertyDelegate, but that has changed since. See this post for more information.
The official #State documentation has the following to say:
SwiftUI manages the storage of any property you declare as a state.
When the state value changes, the view invalidates its appearance and
recomputes the body. Use the state as the single source of truth for a
given view.
A State instance isn’t the value itself; it’s a means of
reading and mutating the value. To access a state’s underlying value,
use its value property.
So when you initialize a property that's marked #State, you're not actually creating your own variable, but rather prompting SwiftUI to create "something" in the background that stores what you set and monitors it from now on! Your #State var just acts as a delegate to access this wrapper.
Every time your #State variable is written, SwiftUI will know as it is monitoring it. It will also know whether the #State variable was read from the View's body. Using this information, it will be able to recompute any View having referenced a #State variable in its body after a change to this variable.
Let me add something else if you know React Native.
The #State property is very like the this.state object in React Native.
For example:
struct Foobar: some View {
#State var username = ""
}
class Foobar extends React.Component {
constructor(props) {
super(props);
this.state = {
username: '',
};
}
}
When you modify the username variable, they will have the same effect, that re-render the current page.
Its explained nicely with an example in the WWDC video - Session 204 (starts at 16:00, quotation starts at 20:15)
One of the special properties of #State variables is that SwiftUI can observe when they're read and written. Because SwiftUI knows that zoomed was read in body, it knows that the view's rendering depends on it. Which means - when a variable changes the framework is going to ask for body again using the new #State value.
The #State as a Property Wrapper is also elaborated and justified in Data Flow Through Swift UI (5:38) WWDC vid as well. It's shown how it solves the problem when we need a mutable value in an immutable (struct) View.
If you click into #State you can see that it has several getters. One with Value another with Binding<Value>.
SwiftUI seems to rely heavily on reactive programming (and their new Combine framework, and since we cannot see the full implementation of these wrappers, I would expect that the values that are stored through #State property wrappers are being managed by a CurrentValueSubject from Combine. Like the name implies, this essentially stores the current value, which can then be used as a bindable property by using the $ syntax.
I like how profesor Paul Hegarty from Stanford explain it. He said that #State basically convert that variable into a pointer to some boolean somewhere else in memory and that's where the value change. But your variable - now a pointer with #State- does not change, is always pointing to that place in memory.
Note:- The accepted answer is correct but incase you are trying to look for a easier explanation I tried below
#State property wrapper allow us to change values inside a struct.
Note:- You cannot change a property within a struct as its a values types, so its not allowed.
struct ExampleTextView: View {
// Declare a variable with state property wrapper
#State private var shouldChangeText: Bool = false
var body: some View {
Text("Just an example")
.foregroundColor(Color.white)
}
}
Incase you are wondering should we add a private access specifier?
Yes, as a rule of thumb apple recommends #State propertise shouldn't be
shared with other views as there are more specific property wrappers for
that #ObservedObject and #EnvironmentObject.
But if it's value type how it can be mutated where is it stored then?
So whenever we are marking a property with #State we move its storage out
from the struct into the shared storage managed by SwiftUI.
In case in your mind if you are comparing with Swift, this is how its done there,
struct Example {
var exampleType: String
mutating func changeType() {
exampleType = "Are we allowed to do this?"
}
}
Credit: Please note this answer is inspired by this post https://www.hackingwithswift.com/quick-start/swiftui/what-is-the-state-property-wrapper
If you know about C# and windows development. #State is similar if not the same as x:Bind or Binding.. On a collection it is similar if not the same as ObservableCollection.
As fredpi said, SwiftUI is listing for updates on vars with the #State property delegate.

Swift Instance Variable Underscore Prefix?

Did Swift drop the underscore-prefix convention for instance variables, e.g., _window? If so, why?
Apple still uses _ in its Xcode boilerplate code as a convention for a non-public variable. You'll see a pattern like such:
class Foo {
var _bar : Bar? = nil
var bar : Bar {
if _bar == nil {
/* compute some stuff */
_bar = Bar (/* ... */)
}
return _bar!
}
}
where access to the property is meant to be through the bar computed property. You find this in Apple CoreData templates.
In Objective-C when you declare a property #synthesize would create the getter and setters for you automatically since clang 3.2. So, the default #synthesize for a property "foo" would look like this:
#synthesize foo = _foo
because of that _foo would then be the iVar. In other words you could have done the #synthesize yourself and called the iVar whatever you liked:
#synthesize foo = myiVarFoo
so in this case there is no "_"
So now in Swift from the documentation:
Swift unifies these concepts into a single property declaration. A Swift property does not have a corresponding instance variable, and the backing store for a property is not accessed directly.
So from the documentation it's clear that swift does not have a corresponding instance variable thus no need to have the "_" around anymore.
The underscore prefix was meant not to confuse the instance variable _foo with its getter foo.
In swift there's not such distinction between ivars and getters. Instead you only have properties, making the _ convention non necessary.
The answer is no because there are no "instance variables" right now in Swift. Only properties (stored properties and computed properties).
I'd say this _underscoreName convention is dropped (although some Apple templates still have it).
Swift's "Lazy Stored Properties" make _these unnecessary. This post:
http://mikebuss.com/2014/06/22/lazy-initialization-swift/
explains it well.
I use a leading underscore to denote a private symbol.
Yes, the underscores do hamper readability at first, but there is a valuable payoff in comprehension and maintainability.
e.g.:
final class SomeClass
{
fileprivate let _kMagicNumber: CGFloat = 3.14
fileprivate struct _PrivateInfo
{
let foo: Int
let bar: String
}
fileprivate var _privateInfo: _PrivateInfo
fileprivate func _setup(with info: _PrivateInfo) { ... }
}
etc.
At a glance, you can see which elements belong where.
You don't need to option-click or do the "who does this belong to?" dance.
Code comprehension shouldn't rely on an IDE's features. And there are times (GitHub, raw text files) where an IDE isn't available.
I understand the "it's not convention" argument. But conventions aren't written on stone tablets. Swift is rapidly evolving, as is our usage of it.
If the Swift team were to produce an annotation syntax for private symbols tomorrow, I'd use it. But until then...
Since I've got my soapbox out, please prefix your extensions.
Consider this snippet:
let color = "#ff7733".hexColor
Where does the "hexColor" come from? Your own code? The Swift standard library? Foundation? UKit? (Hah!) A CocoaPod? Who knows?
(Seasoned CocoaPods users will know that every second open-source library implements a "hexColor" property. With all the problems that entails.)
So, given a company or project name like "Double Secret Probation", consider using:
let color = "#ff7733".dsp_hexColor
Finally, I strongly recommend the books "Writing Solid Code" and "Code Complete".
The convention of a prefixing private vars long preceeded that of ObjCs (weird) property synthesis concept. Clarity was the original reason for such a prefix, not differentiation though it was useful and common to expose a public getter without the underscore...for obvious reasons. IMO, ObjC prop synthesis just put a big fat monkey wrench in the works confusing the h*** out of everyone...
What if you wanted a private synthesized property? In order to underscore-prefix your private synthesized property, you'd need a double underscore backing var. Apple specifically warned against double underscores and this created confusion. Should we bother to use synth'ed properties internally or stick with the backing var (which still had an underscore and was clearly private)? Should we just stop differentiating between private and public vars? Why??
In practice people would use the synthesized version internal to a class as a kind of smart setter, if and only if they wanted the smarts – but that broke down the ideal of encapsulation – choosing whether to use the synth'ed setter required apriori knowledge of what happened behind the scenes.
Meanwhile, as pointed out above, apple's internal code still used the convention, sometimes for synthesized properties too IIRC. And they still do for swift properties! But not consistently...The biggest evidence your language design policy is confusing is when your own devs aren't using it consistently!
Clarity was the original motive and it worked well. I say:
BRING BACK THE UNDERSCORE!
...for private vars and methods :)
(P.S. Dart even has this as an actual language convention in lieu of a private keyword!)