Swift places a high premium on type safety. The entire Swift language was designed with safety in mind. It is one of the hallmarks of Swift and one that you should welcome with open arms. It will assist in the development of clean, readable code and help keep your application from crashing.
All optionals in Swift are demarcated with the ?
symbol. By setting the ?
after the name of the type in which you are declaring as optional you are essentially casting this not as the type in which is before the ?
, but instead as the optional type.
Note: A variable or type Int
is not the same as Int?
. They are two different types that can not be operated on each other.
Using Optional
var myString: String?
myString = "foobar"
This does not mean that you are working with a type of String
. This means that you are working with a type of String?
(String Optional, or Optional String). In fact, whenever you attempt to
print(myString)
at runtime, the debug console will print Optional("foobar")
. The "Optional()
" part indicates that this variable may or may not have a value at runtime, but just so happens to currently be containing the string "foobar". This "Optional()
" indication will remain unless you do what is called "unwrapping" the optional value.
Unwrapping an optional means that you are now casting that type as non-optional. This will generate a new type and assign the value that resided within that optional to the new non-optional type. This way you can perform operations on that variable as it has been guaranteed by the compiler to have a solid value.
Conditionally Unwrapping will check if the value in the optional is nil
or not. If it is not nil
, there will be a newly created constant variable that will be assigned the value and unwrapped into the non-optional constant. And from there you may safely use the non-optional in the if
block.
Note: You can give your conditionally unwrapped constant the same name as the optional variable you are unwrapping.
if let myString = myString {
print(myString)
// will print "foobar"
}
Conditionally unwrapping optionals is the cleanest way to access an optional's value because if it contains a nil value then everything within the if let block will not execute. Of course, like any if statement, you may include an else block
if let myString = myString {
print(myString)
// will print "foobar"
}
else {
print("No value")
}
Forcibly Unwrapping is done by employing what is known as the !
("bang") operator. This is less safe but still allows your code to compile. However whenever you use the bang operator you must be 1000% certain that your variable does in fact contain a solid value before forcibly unwrapping.
var myString: String?
myString = "foobar"
print(myString!)
This above is entirely valid Swift code. It prints out the value of myString
that was set as "foobar". The user would see foobar
printed in the console and that's about it. But let's assume the value was never set:
var myString: String?
print(myString!)
Now we have a different situation on our hands. Unlike Objective-C, whenever an attempt is made to forcibly unwrap an optional, and the optional has not been set and is nil
, when you try to unwrap the optional to see what's inside your application will crash.
Unwrapping w/ Type Casting. As we said earlier that while you are unwrapping
the optional you are actually casting to a non-optional type, you can also cast the non-optional to a different type. For example:
var something: Any?
Somewhere in our code the variable something
will get set with some value. Maybe we are using generics or maybe there is some other logic that is going on that will cause this to change. So later in our code we want to use something
but still be able to treat it differently if it is a different type. In this case you will want to use the as
keyword to determine this:
Note: The as
operator is how you type cast in Swift.
// Conditionally
if let thing = something as? Int {
print(thing) // 0
}
// Optionally
let thing = something as? Int
print(thing) // Optional(0)
// Forcibly
let thing = something as! Int
print(thing) // 0, if no exception is raised
Notice the difference between the two as
keywords. Like before when we forcibly unwrapped an optional we used the !
bang operator to do so. Here you will do the same thing but instead of casting as just a non-optional you are casting it also as Int
. And it must be able to be downcast as Int
, otherwise, like using the bang operator when the value is nil
your application will crash.
And in order to use these variables at all in some sort or mathematical operation they must be unwrapped in order to do so.
For instance, in Swift only valid number data types of the same kind may be operated on each other. When you cast a type with the as!
you are forcing the downcast of that variable as though you are certain it is of that type, therefore safe to operate on and not crash your application. This is ok as long as the variable indeed is of the type you are casting it to, otherwise you'll have a mess on your hands.
Nonetheless casting with as!
will allow your code to compile. By casting with an as?
is a different story. In fact, as?
declares your Int
as a completely different data type all together.
Now it is Optional(0)
And if you ever tried to do your homework writing something like
1 + Optional(1) = 2
Your math teacher would have likely given you an "F". Same with Swift. Except Swift would rather not compile at all rather than give you a grade. Because at the end of the day the optional may in fact be nil.
Safety First Kids.