Swift-like Swift code

A brief introduction to Swift optionals.

swift_swarm

Swift is becoming the language of choice for more and more developers on iOS and OS X. It’s fast, simple, clean, and has a number of features that simply aren’t available to Objective-C programmers.

While it isn’t a hard requirement to do so, several projects are being ported from Objective-C to Swift — especially those in their early stages — in order to take advantage of the speed, power, and safety of Swift. One of those projects isn’t actually a software project — it’s the upcoming Swift edition of iOS Games Programming Cookbook. When we began updating the book for Swift, the first thing that we had to do was to rewrite all of the book’s code in the new language. However, a straight re-write from one language into another isn’t enough. Swift behaves differently than Objective-C in very important ways, and that means that your ported Swift code needs to be aware of how Swift does things.

Avoid implicitly unwrapped optionals

Optionals are one of the most interesting features of the Swift language. They deal with the problem of null in a very clever way: never all objects to be nil, except for one special class, called an optional. A string variable, for example, must always contain a string of some sort, and is never allowed to be nil — that is, it’s never allowed to not contain a string. An optional string, by contrast, is allowed to contain nil. In order to help you keep track of what’s optional and what’s not, Swift requires that you use special syntax when dealing with optionals.

When you create an optional string, you use the ? character:

var optionalString : String?

Whenever you want to use this optional string, you must first check to see if the optional contains a value, again using ?; if the variable doesn’t contain a value, evaluation of the expression stops.

optionalString?.length // will only run if optionalString is not nil

As an aside, if the variable does contain a value, any properties or results of methods that you run on that value become optional as well. For example:

var myString = "Hello"
var myStringLength = myString.utf16Count // = non-optional Int

var myOptionalString : String? = "Hello"
var myOptionalStringLength = myOptionalString?.utf16Count //optional Int

All of this use of the ? character can lead to some confusing error messages if you don’t understand what’s going on. Let’s take a look at that last line again, but with one character changed:

var myOptionalStringLength = myOptionalString.utf16Count

If you try this, Xcode will produce the following error:

'String?' does not have a member named 'utf16Count'

At first glance, this error message doesn’t make much sense, because we know for a fact that strings have a property called utf16Count. However, it’s made easier when you realize that optionals are an entirely different type to strings. An optional string variable happens to contain a string (sometimes), but it doesn’t have anything else to do with the value. In fact, here’s the definition of optionals, in the Swift library:

enum Optional<T> : Reflectable, NilLiteralConvertible {
    case None
    case Some(T)

    /// Construct a `nil` instance.
    init()

    /// Construct a non-\ `nil` instance that stores `some`.
    init(_ some: T)

    /// If `self == nil`, returns `nil`.  Otherwise, returns
    `f(self!)`.
    func map<U>(f: (T) -> U) -> U?

    /// Returns a mirror that reflects `self`.
    func getMirror() -> MirrorType

    /// Create an instance initialized with `nil`.
    init(nilLiteral: ())
}

As you can see, an optional is a complete type on its own. It just happens to contain a value (represented by the generic type T, defined on the first line). So, the compiler is being entirely truthful when it says that “myOptionalString” has no property called “utf16Count”. You need to unwrap the optional using the ? character.

However, too many ?‘s can end up cluttering your code. Additionally, the fact that any value you get as the result of unwrapping an optional is itself optional can just get annoying.

As an alternative, you can declare an optional to be implicitly wrapped. What this means is that you get a variable that is allowed to be nil, but when you attempt to access the value of the variable, you don’t need to unwrap it using ? — you ask for the value, and you get it. This means less messy code!

var myImplicitString : String! = "Hello"

myImplicitString.utf16Count // works!
myImplicitString = nil // also works!

The problem with implicitly unwrapped optionals is that there’s zero safety. If you attempt to access the value of an implicitly unwrapped optional, and it’s nil, your program crashes. This is actually deliberate: the whole point of optionals is to make you think about when values have a chance of being nil, and when they’re always going to contain a valid value. Implicitly unwrapped optionals short-circuit this protection.

If you want to make your code cleaner, don’t use implicitly unwrapped optionals. Instead, use the if let syntax:

if let theString = myOptionalString {
    // do work with theString, which is guaranteed to be non-nil
    // you also don't need to use ? to access the value
}

The if let syntax lets you perform optional binding — checking the value of an optional, and binding it to a constant value that’s guaranteed to never be nil. You can do all of your work with this constant, safe in the knowledge that you’re working with a real, valid value.

if let also lets you safely perform typecasts. Say, for example, you’ve got an object of type AnyObject — meaning that it could be literally any kind of object:

var someObject : AnyObject = ...

Let’s also say that you’re pretty sure that this is an NSURL, and you want to do some work with it.

let someURL = someObject as NSURL

If someObject isn’t actually convertible to a NSURL, your program will crash. Instead, you should use if let with the as? operator to check to see if it’s convertible, and if it is, bind the result to a constant that you can use:

if let someURL = someObject as? NSURL {
    // code here will only run if the typecast is successful
    // in here, 'someURL' is guaranteed to be a valid NSURL object
}

As we’ve seen, there are much better ways to deal with value and type ambiguity in Swift than to fall back to unsafe checks and it’s much more preferable to use Swift’s built-in support for safely checking. In the next article, we’ll talk about some more Swifty ways to work with your code.

Editor’s note: if you’d like to dive deeper into learning Swift, check out Ultimate Swift Programming video training with Jon Manning, Paris Buttfield-Addison, and Tim Nugent. It’s free to start and offers over 12 hours of the best Swift training available.

This post is the first part of a series on Swift-like Swift code and is part of our ongoing exploration into expanding the notion of mobile.

Cropped swift image CC BY 2.0 blue velcro

tags: , , , ,