What does the underscore mean before a variable in Swiftui in an init()? - swift

What does the underscore mean before momentDate? Why is it needed?

The underscored variable name refers to the underlying storage for the Binding struct. This is part of a language feature called Property Wrappers.
Given one variable declaration, #Binding var momentDate: Date, you can access three variables:
self._momentDate is the Binding<Date> struct itself.
self.momentDate, equivalent to self._momentDate.wrappedValue, is a Date. You would use this when rendering the date in the view's body.
self.$momentDate, equivalent to self._momentDate.projectedValue, is also the Binding<Date>. You would pass this down to child views if they need to be able to change the date.
For Binding, the "projected value" ($) is just self, and the difference between _ and $ is only in the access level. However, other property wrappers may project a different type of value (see the #SmallNumber example in the language guide).

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

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

Is it valid to set the value of changing control property equal to a constant in swift?

I apologize for the rather basic question, there is a lot of documentation out there but this is not particularly clear to me.
Swift keeps giving me warnings that suggest changing variables to constants so my question is this: if I set a constant equal to a control property (a label text value for instance) and the value of that control property changes, will the value of the constant change? The definition of that "constant" will always be equal to the control property.
Example from my code:
let MELLandingPenalty: Int = Int(lblMELLandingDist.text!)!
Constants behave in two different ways:
If the assigned object is value type then the value is a copy of the right side and will never change.
If the assigned object is reference type then the reference will never change but its variable properties are mutable.
In your example value type MELLandingPenalty will never change – by the way variable names are supposed to start with a lowercase letter and don't annotate types the compiler can infer.
Trust the compiler and resolve the warnings by changing var to let.

Swift. When should you define an Object / Value with specific data type

As I started developing with Swift and searching through different tutorials and documentations about the language, I'm not sure about one thing.
You can declare an object / value with a specific data type like this:
var aString:String = "Test"
var anObject:SKScene = ASceneClass()
Or you can just do it like this:
var aString = "Test"
var anObject = ASceneClass()
The result will be exactly the same (ASceneClass inherits from SKScene of course)
As everyone is doing it different I wonder if there's a logical reason behind it or you do it for readability ?
Declaring type right after variable name is called Type Annotation
When you don't do that, you have to provide initial value
var aString = "Test"
Often value is not known at that moment, or you are not even sure if it's going to be not nil value, then you can declare it as optional
var aString:String?
If you would like to declare variable without any initiaization but you are sure it's not going to evaluate to nil, you force unwrap it
var aString:String!
This is the definition. In practice, it's always better to use type annotations even when you initialize variable with value, because later in your program you will notice anytime you mess something with the type of the variable.
Also, When you declare an array or dictionary, usually nested ones, Xcode might expect them to have type annotations since it might have some issues with writing values when the type is not known in advance.
To recap
You will want to use type annotations whenever you can, which means whenever you are sure about the variable's type in advance
Recommended/Documented way to declare a variable in swift is as follow:
var <variable name>: <type> = <initial value/expression>
Note: Given form declares a stored variable or stored variable property. Its used when you are clear about type annotation of it.
Though its valid to declare variable without its Type.
var variableName = <initial value>
Note: When you don't know type annotation its mandatory to assign 'Initial value' to that variable.
Refer Swift Documentation on Declaration for more details.

Modifying content of immutable array in Swift does not work

Silly beginner Swift question:
I am expecting the following 3 lines of code to work in the playground:
let items = ["Apple", "Orange", "Pear"]
items[1] = "Banana" // error here
items
Now the error
error: '#lvalue $T5' is not identical to 'String'
items[1] = "Banana"
My understanding that updating content of immutable array is possible in Swift.
I use XCODE 6.1.1
Any idea what is going on here?
Thanks
Based on this thread this was possible in previous releases:
Why in immutable array in swift value can be changed?
When you write let, you define an immutable variable. Use var instead; this lets you define a variable that is mutable.
as stated before me- use a var array if you wish to change your array.
a bit below the question you posted a link and an answer was given inside:
Array in Swift has been completely redesigned to have full value
semantics like Dictionary and String have always had in Swift. This
resolves various mutability problems – now a 'let' array is completely
immutable, and a 'var' array is completely mutable – composes properly
with Dictionary and String, and solves other deeper problems. Value
semantics may be surprising if you are used to NSArray or C arrays: a
copy of the array now produces a full and independent copy of all of
the elements using an efficient lazy copy implementation. This is a
major change for Array, and there are still some performance issues to
be addressed. Please see the Swift Programming Language for more
information. (17192555)
The use of the let keyword declares a Constant.
By definition, a constant cannot be modified.
You want to use the var keyword to declare a Variable,
hence things that will/may vary.
From the apple Swift documentation:
Constants and Variables
Constants and variables associate a name (such as
maximumNumberOfLoginAttempts or welcomeMessage) with a value of a
particular type (such as the number 10 or the string "Hello"). The
value of a constant cannot be changed once it is set, whereas a
variable can be set to a different value in the future.
Declaring Constants and Variables
Constants and variables must be declared before they are used. You
declare constants with the let keyword and variables with the var
keyword. Here’s an example of how constants and variables can be used
to track the number of login attempts a user has made:
let maximumNumberOfLoginAttempts = 10
var currentLoginAttempt = 0