Swift – constants, variables, optionals

Swift 3 Tutorial – Fundamentals

Constants and Variables

Any Swift variable is either a constant or not.

constants and variables are just ways to describe terms that hold a value which can change (are mutable), and constants that can not be changed (becuase they are immutable)

To define a constant, use the let keyword

Example:

let name = “Jameson”
If you were to try and change the value of name, you would be unable to do so, and the Swift compiler would produce an error.

let name = “Jameson”
name = “Bob”
error: cannot assign to value: ‘name’ is a ‘let’ constant
name = “Bob”
~~~~ ^

On the other hand, by using the var keyword, we define a variable that can change

var name = “Jameson”
name = “Bob”
This code does not produce an error.

In general, you should always default to using the let keyword, unless you know you need a var keyword.

This leads to code that is ultimately safer. If you define a constant, and later attempt to modify it, you will get an error and at that time can determine if you should switch to use the var keyword, or if the error is giving you a hint that maybe you should rethink the current logic flow.

In general, immutability is preferred over mutability; it simply leads to less programmers errors and makes it easier to reason about your code.

Basic Types

In Swift, a type is indicated by declaring a variable, then putting a colon, followed by the type name. For example to declare an integer, which is of Swift type Int, you could use the following:

Or similarly, if you want to declare a string:

Swift supports type inference, which means the compiler determine what the type should be based on its initial value. Hence, you can usually omit the type information.

Working with Strings

It’s frequently useful to print a command to the console or otherwise evaluate a String containing other variables. For example, I might want to form a sentence with my variables age and name and print it to the console. I can do this using the + operator between each String.

result:
Robb is 15

A shortcut for this is to write your String as you normally would without the + operator separating each string, and put each variable inside of a set of parentheses, proceeded by a backslash \.

result:
Robb is 15

One thing you may have noticed is that age is now of type String because it was assigned the value “15” instead of just 15 without the quotes. This is because concatenating a String and an Int will not automatically cast the Int to String, which is a necessary step before concatenating is possible.

Non-Optionals and Optionals

https://drewag.me/posts/2014/07/05/what-is-an-optional-in-swift

What is the Problem
In C, it is possible to create a variable without giving it a value. This would look something like this:

If you were to try to use the value before assigning it a value, you would get undefined behavior (that is very bad).

In contrast Swift, for safety reasons, requires all variables and constants to always hold a value. This prevents that scenario where the value of a variable can be unknown. Thus, in swift, by default, we have non-optional values.

They always have a value. If you tried to assign nil to a non-optional variable, you will get a compiler error:

error: nil cannot be assigned to type ‘String’

Similarly, non-optional values can not be assigned to nil during their declaration:

error: variables must have an initial value

However, there are still cases in programming where one wants to represent the absence of a value.

A great example of this is when performing a search. One would want to be able to return something from the search that indicates that no value was found.
Thus, the concept of an optional is introduced:

An optional is just a variable that can be nil, null, or otherwise not set to any value.

How is an Optional Defined

To solve this problem, Swift created the type Optional that can either hold no value (None) or hold some value (Some). In fact, because Swift allows enums to have associated values, an optional is defined as an enum:

You declare an optional version of a type by adding a ? after the type name (String?).

Let’s use favoriteColor as an example. Many people have a favorite color, but it’s possible someone doesn’t, or we just don’t have the data. We would declare this variable as an optional, and not assign it to any value.

Implicit in the declaration of an optional with no value set, is the assignment to nil. We can verify this by examining the value of favoriteColor after declaring it as an optional by printing it to the console using the print() function.

result:
nil

We can later assign something to favoriteColor and see that it is no longer nil.


result:
Optional(“Blue”)

Note that instead of just getting the string “Blue”, we get Optional(“Blue”). This is because the value is still “wrapped” inside of the optional.

Unwrapping Optionals

  • optional binding
  • force-unwrapping

Before you use the value from an Optional you must first “unwrap” it. We consider an optional value “wrapped” because the real value is actually held inside the enumeration.

Let’s look at an example. Here we will declare two optionals, one called favoriteAnimal which is set to Fox, and one set to favoriteSong, which we will not set (it will remain nil)

You can unwrap an optional in both a “safe” and “unsafe” way

The safe way is to use Optional Binding:

In this case, we create a constant variable on the local stack. Assign our optional variable’s value to it, which is nil. the if/else statement evaluates the nil, and goes to the else block.


result:
I don’t know what your favorite song is!

Let’s employ optional binding to discover if each variable is set, and if so we’ll print a sentence containing the value to the console. First we’ll do it with favoriteAnimal. When we assign a constant to an optional Variable, it takes on the value. If the value exist, we make it print.


result:
Favorite animal is: Fox

In the event that the value is not set, we simply will trigger whatever is in the else block, or nothing at all if an else block isn’t specified.

Forced Unwrapping- you assert that it does indeed hold a value

A forced unwrapping, is an optional that doesn’t need to be unwrapped because it is done implicitly. These types of optionals are declared with an ! instead of a ?. Sometimes you know for sure that a variable holds an actual value and you can assert that with Forced Unwrapping by using an exclamation point (!):

If possibleString were None (did not hold a value), the whole program would crash with a runtime error and therefore, forced unwrapping is considered “unsafe”.

Implicitly unwrapped optional

ref – https://drewag.me/posts/2014/07/05/uses-for-implicitly-unwrapped-optionals-in-swift

There are a few main reasons that one would create an Implicitly Unwrapped Optional. All have to do with defining a variable that will never be accessed when nil because otherwise, the Swift compiler will always force you to explicitly unwrap an Optional.

Situation: A Constant That Cannot Be Defined During Initialization. In other words, WHEN YOU HAVE A PROPERTY THAT CAN’T BE POPULATED DURING INITIALIZATION.

Every member constant must have a value by the time initialization is complete.

Sometimes, a constant cannot be initialized with its correct value during initialization, but it can still be guaranteed to have a value before being accessed.

  1. the Optional is automatically initialized with nil, and can be printed only. However, if you try to dereference it, it will crash. Hence make sure you use chaining in order to dereference it
  2. the value it will eventually contain will still be immutable

However, the problem is, it can be a pain to constantly unwrap a variable that you know for sure is not nil via Forced Unwrapping, or Optional Binding.

Solution: Implicitly Unwrapped Optionals achieve the same benefits as an Optional with the added benefit that one does not have to explicitly unwrap it everywhere.

“Because the value of an implicitly unwrapped optional is automatically unwrapped when you use it, there’s no need to use the ! operator to unwrap it. That said, if you try to use an implicitly unwrapped optional that has a value of nil, you’ll get a runtime error.”

As long as your implicit optional is initialized during creation or at another time, you can access and it will be valid.

Like an optional, an implicit optional will also have nil by default during creation. We can initialize the creation of an implicit optional by assigning it data during creation, or at a later time as shown above. Then when we try to access it, it will be valid.

However, if we try to access it without some kind of initialization, we’ll get a compiler error like so:

an implicitly unwrapped optional promises the compiler it has a value when it is accessed

If you create an implicit optional, and somehow set it to nil at a later time, you’ll print out the nil instead.

Take Note

When you create a constant, this means the reference is immutable. That reference points to an object and that object only. you cannot change the reference to any other objects. Thus, by definition, you start off with the reference opVar2 pointing to a Optional object with data of type String. That’s why when you try to use it right after the declaration, you get a compiler error.

Result:

(lldb) po opVar2
▿ Optional
– some : “”

(lldb) po opVar3
nil

Because opVar3 is a mutable reference, it just points to nil as its default initialization. This means you can freely assign assign the reference to different String objects later.

ref – https://krakendev.io/when-to-use-implicitly-unwrapped-optionals/

A great example of this is when a member variable cannot be initialized in a UIView subclass until the view is loaded:

another example:

http://stackoverflow.com/questions/24006975/why-create-implicitly-unwrapped-optionals

1. A Constant That Cannot Be Defined During Initialization

Every member constant must have a value by the time initialization is complete. Sometimes, a constant cannot be initialized with its correct value during initialization, but it can still be guaranteed to have a value before being accessed.

Using an Optional variable gets around this issue because an Optional is automatically initialized with nil and the value it will eventually contain will still be immutable. However, it can be a pain to be constantly unwrapping a variable that you know for sure is not nil. Implicitly Unwrapped Optionals achieve the same benefits as an Optional with the added benefit that one does not have to explicitly unwrap it everywhere.

A great example of this is when a member variable cannot be initialized in a UIView subclass until the view is loaded:

Here, you cannot calculate the original width of the button until the view loads, but you know that viewDidLoad will be called before any other method on the view (other than initialization). Instead of forcing the value to be explicitly unwrapped pointlessly all over your class, you can declare it as an Implicitly Unwrapped Optional.

2. Interacting with an Objective-C API

Every reference to an object in Objective-C is a pointer, which means that it can be nil.
That means, that every interaction with an Objective-C API from Swift must use an optional where there is a reference to an object.

You could use a normal Optional in every one of these cases, but if you know for sure that the reference will not be nil, you can save yourself unwrapping code by declaring it as an Implicitly Unwrapped Optional.

Here, you know that the method will never be called without a tableView or indexPath.
Thus, the parameters are declared as implicitly unwrapped optional. You can safely use the dot operator
on tableView, and cellForRowAtIndexPath.

3. When Your App Cannot Recover From a Variable Being nil

This should be extremely rare, but if your app could literally not continue to run if a variable is nil when accessed, it would be a waste of time to bother testing it for nil.

Normally if you have a condition that must absolutely be true for your app to continue running, you would use an assert. An Implicitly Unwrapped Optional has an assert for nil built right into it.

4. NSObject Initializers

Apple does have at least one strange case of Implicitly Unwrapped Optionals. Technically, all initializers from classes that inherit from NSObject return Implicitly Unwrapped Optionals. This is because initialization in Objective-C can return nil. That means, in some cases, that you will still want to be able to test the result of initialization for nil. A perfect example of this is with UIImage if the image does not exist:

If you think there is a chance that your image does not exist and you can gracefully handle that scenario, you can declare the variable capturing the initialization explicitly as an Optional so that you can check it for nil. You could also use an Implicitly Unwrapped Optional here, but since you are planning to check it anyway, it is better to use a normal Optional.

Optional Chaining

Adding ? to the end of a type makes it Optional.
Adding ? to the end of an optional variable invokes Optional Chaining.

You specify optional chaining by placing a question mark (?) after the optional value on which you wish to call a property

…method or subscript if the optional is non-nil. This is very similar to placing an exclamation mark (!) after an optional value to force the unwrapping of its value.

The main difference is that optional chaining fails gracefully when the optional is nil, whereas forced unwrapping triggers a runtime error when the optional is nil.

Hence if you declare an optional object in your class, and you want to access that object’s properties, you must use the “?” on the optional object in order to get the valid unwrapped object. That you can continue to access the unwrapped object’s values. If you just use “.” without the “?”, the optional object is looked upon as an enum, and thus, you’ll get an error.

example:

we use ? after navigationController, this is called optional chaining
the reason why is because navigationController is an optional var.
in order to access properties of an optional var (or chaining),
we use someVar?.

if we do not do this, and try to use the dot notation to access properties straight on the variable like this:

essentially, what’s happening is that you are trying to access the enum of the optional var “someVar” instead. That is incorrect.

Thus, in order to access the properties of optional variable make sure to use

optional-chaining