• 20 heures
  • Moyenne

Ce cours est visible gratuitement en ligne.

course.header.alt.is_video

course.header.alt.is_certifying

J'ai tout compris !

Mis à jour le 27/04/2023

Understand the optionals

We’ve solved Jenny’s problem at hand with a rather elegant solution. We can now use comprehensive key to access each element and don’t have to remember the indices anymore!

Well... almost solved!

What if, down the road Jenny decides to add more variety to her shop, like selling fancy coffee cups, and we attempt to calculate the profit for this new category but forget to add it to the the initial collection in the first place? or simply mistype a key? TROUBLE - TROUBLE!

In this chapter we are going to address such situations by learning about Optionals.

Introducing Optionals

Optionals are basically something that is potentially available but may not be there (yet) .

Declaring optionals

To declare an optional variable we use a question mark, ? , right after its type:

var myOptionalVariable: String? = "Potential text"

Then, we try to access it:

print(myOptionalVariable)

In console we can observe the following:

Optional("Potential text")

Notice that it didn't simply print the value we assigned to it?  It identified it as Optional!

Remember how earlier we stated that a variable must be initialized in order to be accessed? Let's do a few more examples in Playground:

// not using optional
var nonOptionalString: String // Ok
print(nonOptionalString) // Error

// using optional
var optionalString: String? // Ok
print(optionalString) // Ok

As before, we can see that Playground generated an error when we tried to access the  nonOptionalString   variable without previously initializing it.

Why doesn't this happen when we use optionals?

Using optionals puts the responsibility on developers for the safe usage of variables . It also allows for using variables that, depending on the logic in a program, may not be required to contain any value at all!

For example, you likely had to fill out a number of online forms to register for an event, for example. You could be asked some required information, such as your name and email and some optional, like a phone number or address. In this case a developer would still need to have variables ready for your input of a phone number and address, but may never receive any value should you decide to keep this information private :diable:!

What does that Optional mean exactly o_O?

Is it your Birthday yet?

Think of it as a Gift box. You get a present for your bday and can clearly see a nice box with a bow. You wanted a new Apple watch and the box appears to be of a matching size :waw:!

Anticipation is always pleasant!
Anticipation is always pleasant!

Now you are getting excited about a new gadget and already thinking about ordering a new sports band!

Wait a minute, what if it’s a mean joke and the box is empty?! Not to crash your dreams further but first you need to make sure that the watch is in the box!

A use case for that is if you have declared a variable but haven’t initialized it, yet (in other words, you haven’t assigned any value to it, yet). To be able to use it, it must be initialized (a value must be assigned). When the code is short and simple, we can make sure we do things in order and have everything we need at any given moment.

However, as the code gets more complex, each part of the code has to protect itself. We need to make sure we test the waters before stepping in! This is called UnWrapping (opening the gift).

Unwrapping  Optionals

There are 3 ways to unwrap optionals:

  • A quick, but dangerous method

  • And 2 safe ones

Quick unwrapping

The quick and dangerous methods is when we act like the value is there and insist on accessing it. Unwrapping with this method allows us writing less code (as the definition states - it's quick:)). However, we have to be careful using it. It should only be used when we are absolutely sure that the value is there.

In our gift box example, if you happened to be in an Apple store, and you witnessed your friends huddled together, but they didn’t see you...well, that would be a reasonably sure sign that the gift is, in fact, an apple watch ;).

To quickly unwrap an optional we simply place an exclamation mark   !   after the name of a variable.

Here's an example when we are surely assigning a value to an optional, so we can use the quick method ( (notice an exclamation mark after the variable name in print function):

var myOptionalVariable: String? = "Potential text"
print(myOptionalVariable!)

After executing this code in Playground we can observe the result in console:

Potential text

As you can see, it was no longer  Optional("Potential text")   like in the beginning of this chapter. This is because we explicitly indicated that a value IS there.

Now, if we don't assign any value to a variable but apply the same brut force unwrapping it, we get an error:

var myOptionalVariable: String?
print(myOptionalVariable!) // Error

At this time, it's a different type of error: a runtime error

The Playground editor shows: "error: Execution was interrupted, reason: EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0)." and console states: "fatal error: unexpectedly found nil while unwrapping an Optional value".

Which basically means our program crashed  :pirate:!

Poof!
Poof!

Before we move on to the safe methods.

If quick method should be used when we are sure(!) the value is there. And if we are sure, why does it have to be optional?

This is indeed confusing. However, the important thing to consider is that our programs are typically more complex than the examples we use in this course. And more importantly, same variables are used in different parts of an application - written by the same or different developers.

While working with the same variable in one part of the code we can be "sure" the value is there, when in other parts, it's not guaranteed. 

Taking form example with optional phone number, the variable must be optional as we can't request that user always provides a number. When in some parts of the code we may decide to always have a default value - in which case we can use a quick unwrapping after. And in other cases we leave it as is and must always check what was supplied by a user.

So, if we are not absolutely sure the value is there, it's best to use one of the 2 safe methods using if/else statements.

Safely unwrapping optionals - method #1

Instead of trying to access a variable directly, we can compare it to nil (nothing), and if it's not nil, we can use it safely:

var optionalString: String?

if optionalString != nil {
    print(optionalString!)
}

Observe that nothing is printed in console as a result of this execution. We didn't assign any value to our variable, therefore it's nil. The if condition wasn't met and the print function was not executed.

If we now assign some text to our variable:

var optionalString: String?

optionalString = "Finally some text!"

if optionalString != nil {
    print(optionalString!)
}

It will produce an output in console:

Finally some text! 

This time our variable contains some text- it's no longer nil. The if condition is met and the print function was executed.

Safely unwrapping optionals - method #2

You notice that in the first safe method we still had to use the exclamation mark  !   to unwrap our variable within the if block after verifying that it has a value. 

Another safe method is to temporarily assign the value of our variable to a temporary variable or constant within the if statement condition. Next, we use that temporary variable within the if block:

var originalOptionalString: String?

if let temporaryOptionalString = originalOptionalString {
    print(temporaryOptionalString)
}

As you can see, we didn't have to use the exclamation mark  !   when accessing the new variable  temporaryOptionalString . Since this temporary variable is no longer optional, it definitely has a value - it was verified in the conditional expression of our if statement.

You can experiment with the output in the console by assigning a value to the  originalOptionalString   like we did when we described the first safe method.

So, which option to use and when?

Let's repeat:

  • If you are sure the value is there - use a quick method.

  • When in doubt, stay safe - use one of the safe methods! 

How about our calculations for Jenny?

In our code, we’ve already dealt with optionals; our dictionary elements. When we attempt to access a dictionary element, it gives us an Optional, not a guaranteed value!

So, we are yet to improve our program using our new dictionary:

var profits = ["coffee": 0.0, "dessert": 0.0, "food": 0.0]

Replace the array we previously used to store the profits with the new dictionary we just created. As usual, try modifying the code on your own:

// Usual thing - try on your own first!






































var profits = ["coffee": 0.0, "dessert": 0.0, "food": 0.0]

// profit calculation for 2 months
for day in 1 ... 60 {
    if (day % 7 == 5) { // if Saturday
        profits["coffee"]! += (2.70 - (0.50 + 1.00)) * 450 // coffee
        profits["dessert"]! += (5.50 - (3.50 + 0.00)) * 180 // dessert
        profits["food"]! += (15.0 - (7.00 + 5.00)) * 120 // food
    }
    else if (day % 7 != 6) { // other days of the week excluding Sundays
        profits["coffee"]! += (2.70 - (0.50 + 1.00)) * 560 // coffee
        profits["dessert"]! += (5.50 - (3.50 + 0.00)) * 240 // dessert
        profits["food"]! += (15.0 - (7.00 + 5.00)) * 80 // food
    }
}

// find out the most profitable category
if (profits["coffee"]! > profits["dessert"]! && profits["coffee"]! > profits["food"]!) { // compare the first element to the rest
    print("Coffee is the most profitable category")
}
else if (profits["dessert"]! > profits["coffee"]! && profits["dessert"]! > profits["food"]!) { // compare the second element to the rest
    print("Dessert is the most profitable category")
}
else if (profits["food"]! > profits["coffee"]! && profits["food"]! > profits["dessert"]!) { // compare the third element to the rest
    print("Food is the most profitable category")
}

// initial total profit
var totalProfit = 0.0

// put together profits for all categories
for (category, profit) in profits {
    totalProfit += profit
}

// preset the final result
print("The total profit for 2 months is $\(totalProfit)")

Here I used the quick method to unwrap the dictionary elements because I'm absolutely sure the value is there!

Before we finish it off, let's make one tiny improvement. You can see that Playground complains about us (maybe just me, in this case:) ) when we declare and don't use the variable  category  in the last for-in loop above.  To correct that, an unused variable can be replaced with a generic placeholder: the underscore (  _  ):

for (_, profit) in profits {
    totalProfit += profit
}

Playground is happy, now!

Let's Recap!

  • An optional provides a possibility to use a variable without a value.

  • If an optional does not contain a value, its contents are referred to as nil.

  • Like a gift box, an optional value will contain one of the following two variants:

    • A value of an indicated type of a variable 

    • nil - a marker of nothing

  • An optional variable must be unwrapped before it can be utilized, using one of these 3 methods:

    • A quick method with  ! . This will cause the program to crash if a variable that's being unwrapped does not contain a value (in other words, if the value is nil):

      optional!
    • A safe method that checks whether the variable contains a value or not. It's still required to unwrap the variable before use:

      if optional! = nil {
          // here we know the optional contains a value that's still required to be unwrapped
      }
    • A safe method that allows access to the variable by assigning its value to a new temporary variable (most often, a constant) and verifying that it contains a value at the same time.

      if let unwrapped = optional {
          // here we know the optional contains a value that's now acceptible using a new temoprary non-optional variable
      }
  • When accessing elements ​​of a dictionary with a key, the dictionary returns an optional and not a direct value.

Exemple de certificat de réussite
Exemple de certificat de réussite