Ios – an “unwrapped value” in Swift

iosios8swift

I'm learning Swift for iOS 8 / OSX 10.10 by following this tutorial, and the term "unwrapped value" is used several times, as in this paragraph (under Objects and Class):

When working with optional values, you can write ? before operations
like methods, properties, and subscripting. If the value before the ?
is nil, everything after the ? is ignored and the value of the whole
expression is nil. Otherwise, the optional value is unwrapped, and
everything after the ? acts on the unwrapped value. In both cases, the
value of the whole expression is an optional value.

let optionalSquare: Square? = Square(sideLength: 2.5, name: "optional square") 
let sideLength = optionalSquare?.sideLength

I don't get it, and searched on the web without luck.

What does this means?


Edit

From Cezary's answer, there's a slight difference between the output of the original code and the final solution (tested on playground) :

Original code

Original code

Cezary's solution

Cezary's solution

The superclass' properties are shown in the output in the second case, while there's an empty object in the first case.

Isn't the result supposed to be identical in both case?

Related Q&A : What is an optional value in Swift?

Best Answer

First, you have to understand what an Optional type is. An optional type basically means that the variable can be nil.

Example:

var canBeNil : Int? = 4
canBeNil = nil

The question mark indicates the fact that canBeNil can be nil.

This would not work:

var cantBeNil : Int = 4
cantBeNil = nil // can't do this

To get the value from your variable if it is optional, you have to unwrap it. This just means putting an exclamation point at the end.

var canBeNil : Int? = 4
println(canBeNil!)

Your code should look like this:

let optionalSquare: Square? = Square(sideLength: 2.5, name: "optional square") 
let sideLength = optionalSquare!.sideLength

A sidenote:

You can also declare optionals to automatically unwrap by using an exclamation mark instead of a question mark.

Example:

var canBeNil : Int! = 4
print(canBeNil) // no unwrapping needed

So an alternative way to fix your code is:

let optionalSquare: Square! = Square(sideLength: 2.5, name: "optional square") 
let sideLength = optionalSquare.sideLength

EDIT:

The difference that you're seeing is exactly the symptom of the fact that the optional value is wrapped. There is another layer on top of it. The unwrapped version just shows the straight object because it is, well, unwrapped.

A quick playground comparison:

playground

In the first and second cases, the object is not being automatically unwrapped, so you see two "layers" ({{...}}), whereas in the third case, you see only one layer ({...}) because the object is being automatically unwrapped.

The difference between the first case and the second two cases is that the second two cases will give you a runtime error if optionalSquare is set to nil. Using the syntax in the first case, you can do something like this:

if let sideLength = optionalSquare?.sideLength {
    println("sideLength is not nil")
} else {
    println("sidelength is nil")
}
Related Topic