What does the dollar sign do in Swift / SwiftUI?
Asked Answered
F

2

71

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.

Faceharden answered 11/6, 2019 at 20:16 Comment(0)
C
55

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".

Chappell answered 11/6, 2019 at 20:33 Comment(6)
You make it sound like some kind of operator. It isn't. The dollar sign is merely the first letter of the variable name. It doesn't "make" a binding. $aState is the binding.Grantee
The Binding value should be projectedValue, right?Arta
Also docs has a nice example in Projecting a Value From a Property Wrapper at docs.swift.org/swift-book/LanguageGuide/Properties.htmlApostil
@Arta yes, projectedValue of @State property wrapper has type BindingApostil
I am now seeing _aState for @State and @Binding variables, what does it mean? As far as I can see, the underscore does the same as the dollar sign.Faceharden
@Grantee developer.apple.com/documentation/combine/published/… "The projectedValue is the property accessed with the $ operator." What's the "operator"?Arette
G
93

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.

Grantee answered 12/6, 2019 at 17:1 Comment(2)
Neat! The referenced video is here: developer.apple.com/videos/play/wwdc2019/415Retrogressive
Specifically, the property wrapper part of the talk starts at 23:30 ^Retrogressive
C
55

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".

Chappell answered 11/6, 2019 at 20:33 Comment(6)
You make it sound like some kind of operator. It isn't. The dollar sign is merely the first letter of the variable name. It doesn't "make" a binding. $aState is the binding.Grantee
The Binding value should be projectedValue, right?Arta
Also docs has a nice example in Projecting a Value From a Property Wrapper at docs.swift.org/swift-book/LanguageGuide/Properties.htmlApostil
@Arta yes, projectedValue of @State property wrapper has type BindingApostil
I am now seeing _aState for @State and @Binding variables, what does it mean? As far as I can see, the underscore does the same as the dollar sign.Faceharden
@Grantee developer.apple.com/documentation/combine/published/… "The projectedValue is the property accessed with the $ operator." What's the "operator"?Arette

© 2022 - 2024 — McMap. All rights reserved.