The Swift Programming Language guide has the following example:
class Person {
let name: String
init(name: String) { self.name = name }
var apartment: Apartment?
deinit { println("\(name) is being deinitialized") }
}
class Apartment {
let number: Int
init(number: Int) { self.number = number }
var tenant: Person?
deinit { println("Apartment #\(number) is being deinitialized") }
}
var john: Person?
var number73: Apartment?
john = Person(name: "John Appleseed")
number73 = Apartment(number: 73)
//From Apple's “The Swift Programming Language” guide (https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/AutomaticReferenceCounting.html)
Then when assigning the apartment to the person, they use an exclamation point to "unwrap the instance":
john!.apartment = number73
What does it mean to "unwrap the instance"? Why is it necessary? How is it different from just doing the following:
john.apartment = number73
I'm very new to the Swift language. Just trying to get the basics down.
UPDATE:
The big piece of the puzzle that I was missing (not directly stated in the answers - at least not at the time of writing this) is that when you do the following:
var john: Person?
that does NOT mean that "john
is of type Person
and it might be nil", as I originally thought. I was simply misunderstanding that Person
and Person?
are completely separate types. Once I grasped that, all of the other ?
, !
madness, and the great answers below, made a lot more sense.
Some big picture perspective to add to the other useful but more detail-centric answers:
In Swift, the exclamation point appears in several contexts:
let name = nameLabel!.text
var logo: UIImageView!
logo.image = thing as! UIImage
try! NSJSONSerialization.JSONObjectWithData(data, [])
Every one of these is a different language construct with a different meaning, but they all have three important things in common:
1. Exclamation points circumvent Swift’s compile-time safety checks.
When you use
!
in Swift, you are essentially saying, “Hey, compiler, I know you think an error could happen here, but I know with total certainty that it never will.”Not all valid code fits into the box of Swift’s compile-time type system — or any language’s static type checking, for that matter. There are situations where you can logically prove that an error will never happen, but you can’t prove it to the compiler. That’s why Swift’s designers added these features in the first place.
However, whenever you use
!
, you’re ruling out having a recovery path for an error, which means that…2. Exclamation points are potential crashes.
An exclamation point also says, “Hey Swift, I am so certain that this error can never happen that it’s better for you to crash my whole app than it is for me to code a recovery path for it.”
That’s a dangerous assertion. It can be the correct one: in mission-critical code where you have thought hard about your code’s invariants, it may be that bogus output is worse than a crash.
However, when I see
!
in the wild, it's rarely used so mindfully. Instead, it too often means, “this value was optional and I didn’t really think too hard about why it could be nil or how to properly handle that situation, but adding!
made it compile … so my code is correct, right?”Beware the arrogance of the exclamation point. Instead…
3. Exclamation points are best used sparingly.
Every one of these
!
constructs has a?
counterpart that forces you to deal with the error/nil case:if let name = nameLabel?.text { ... }
var logo: UIImageView?
logo.image = thing as? UIImage
try? NSJSONSerialization.JSONObjectWithData(data, [])
If you are tempted to use
!
, it is always good to consider carefully why you are not using?
instead. Is crashing your program really the best option if the!
operation fails? Why is that value optional/failable?Is there a reasonable recovery path your code could take in the nil/error case? If so, code it.
If it can’t possibly be nil, if the error can never happen, then is there a reasonable way to rework your logic so that the compiler knows that? If so, do it; your code will be less error-prone.
There are times when there is no reasonable way to handle an error, and simply ignoring the error — and thus proceeding with wrong data — would be worse than crashing. Those are the times to use force unwrapping.
I periodically search my entire codebase for
!
and audit every use of it. Very few usages stand up to scrutiny. (As of this writing, the entire Siesta framework has exactly two instances of it.)That’s not to say you should never use
!
in your code — just that you should use it mindfully, and never make it the default option.In objective C variables with no value were equal to 'nil'(it was also possible to use 'nil' values same as 0 and false), hence it was possible to use variables in conditional statements (Variables having values are same as 'TRUE' and those with no values were equal to 'FALSE').
Swift provides type safety by providing 'optional value'. i.e. It prevents errors formed from assigning variables of different types.
So in Swift, only booleans can be provided on conditional statements.
Here, even-though 'hw' is a string, it can't be used in an if statement like in objective C.
For that it needs to be created as,
If john were an optional var (declared thusly)
then it would be possible for john to have no value (in ObjC parlance, nil value)
The exclamation point basically tells the compiler "I know this has a value, you don't need to test for it". If you didn't want to use it, you could conditionally test for it:
The interior of this will only evaluate if john has a value.
To put it simply, exclamation marks mean an optional is being unwrapped. An optional is a variable that can have a value or not -- so you can check if the variable is empty, using an if let statement as shown here, and then force unwrap it. If you force unwrap an optional that is empty though, your program will crash, so be careful! Optionals are declared by putting a question mark at the end of an explicit assignment to a variable, for example I could write:
This variable has no value. If I were to unwrap it, the program would crash and Xcode would tell you you tried to unwrap an optional with a value of nil.
Hope that helped.
Here are some examples:
Where
word
is an optional value. means it may or may not contain a value.Here
name
has a value so we can assign itWhere
dog
is forcefully unwrapped means it must contain a valueThe application will crash because we are assign
nil
to unwrappedASK YOURSELF
person?
have anapartment
member/property? ORperson
have anapartment
member/property?If you can't answer this question, then continue reading:
To understand you may need super-basic level of understanding of Generics. See here. A lot of things in Swift are written using Generics. Optionals included
The code below has been made available from this Stanford video. Highly recommend you to watch the first 5 minutes
An Optional is an enum with only 2 cases
Optional binding:
when you say
var john: Person?
You actually mean such:Does the above enum have any property named
apartment
? Do you see it anywhere? It's not there at all! However if you unwrap it ie doperson!
then you can ... what it does under the hood is :Optional<Person>.Some(Person(name: "John Appleseed"))
Had you defined
var john: Person
instead of:var john: Person?
then you would have no longer needed to have the!
used, becausePerson
itself does have a member ofapartment
As a future discussion on why using
!
to unwrap is sometimes not recommended see this Q&A