Since the introduction of Swift, optionals seem to have used a lot of confusion for people learning the language. I have to admit that at the beginning it took me a while too to wrap my mind around them. The cause was that I didn’t take the required time to fully understand them.
My first approach was to just try and use them in my current project, but that did not go well. Question and exclamation marks would pop up here and there, leaving me puzzled on the why. Although I sort of understood what they meant, in many places I did not really know why I was doing something or if it was the correct way or not.
Especially if you are new to programming, it might be hard to see what problems optionals solve or when to use them. Besides this, the operators for optionals (?, !, and ??) cause confusion because they have different meanings in different context.
I am going to first have a look at what optionals are and how they to use them. Then I will talk about what problems they solve, why they are a good idea and how they enforce good practices and better code (in my opinion).
This guide was written for the first version of Swift. I have written a more comprehensive guide on Swift optionals that you can find here.
Table of contents
Why do we need optionals in the first place?
Using optional values: forced unwrapping, optional binding and nil coalescing
Optionals in structures and classes: optional chaining
Avoiding the checks for nil: implicitly unwrapped optionals
Asking an object for its type: downcasting
When a value cannot be initialized: failable initializers
How optionals work under the hood
What is the point of having optionals in Swift?
Why do we need optionals in the first place?
In an ideal world, our code always works on complete and well defined data. Indeed many bugs exist because developers usually write code with this assumption.
Let’s take as an example a common programming exercise: a function to calculate the factorial of an integer. The factorial of a number is the product of all the positive integers up to that number. For example, the factorial of 5 is 1 × 2 × 3 × 4 × 5 = 120. Let’s write a factorial function in Swift:
func factorial(number: Int) -> Int { var result = 1 for var factor = 1; factor <= number; factor++ { result = result * factor } return result } factorial(5) // 120 factorial(7) // 5040 factorial(-3) // 1
Easy enough. All looks good, but if we try to calculate the factorial of -3, our function returns 1, which is not correct. The definition of the factorial states that it exists only for positive numbers, so factorial(-3) should not return a value. How do we represent this?
In many other languages programmers have resorted to return special values to represent results that do not exist. In this case for example we could return -1 to represent “there is no factorial for this number”, since the factorial of a number is always a positive integer by definition. This would work and indeed has been the choice for many programs written in the past.
This is not an ideal solution though. If someone else uses this function, how does he know that -1 means “no result”? Indeed it would not be possible for someone that does not know the definition of the factorial to know whether the result is correct or not. We could write some documentation for the function, but people might ignore it and still use it incorrectly. The incorrect value would then propagate to other parts of their program, causing hard to find bugs.
Many languages use a special value, called nil, to represent the absence of a value. In many of those languages, though, this is possible only for references to objects, leaving simple types like integers out. For these, developers still have to resort to using special values, hoping that some of them are left out the set of valid ones.
Swift solves this problem with optionals. Putting a ? after a type declaration we can state that there could be a value or no value at all, which in Swift it is also represented by nil like in other languages. We can now rewrite our factorial function to return no value for negative numbers:
func factorial(number: Int) -> Int? { if (number < 0) { return nil } var result = 1 for var factor = 1; factor <= number; ++factor { result = result * factor } return result } factorial(-3) // nil
This declaration explicitly states: “the return value might be an integer or a nil value”. This is a key difference with other languages that also use nil values. In those you never know if a value could be nil or not. You need to refer to the documentation, if any. In Swift this is clear from the type, so we always know which values could be nil and which ones will always be valid.
(A little side note: as a reader suggested, the factorial function should check its input through an assertion, making sure that a negative value is never passed. This is because the factorial is undefined for negative parameters, so it should not accept them and leave the checking of the input to the caller. This is a valid approach, but since this is an example to understand optionals, I’ll keep it this way)
Using optional values: forced unwrapping, optional binding and nil coalescing
In Swift, developers are not the only ones to know which values are optional. The compiler knows too and can make a series of checks that are usually not possible in other languages. It is always good to delegate to the compiler as many checks as possible, freeing ourselves from them.
Let’s try to use our new factorial function.
factorial(3) + 7 // Value of optional type 'Int?' not unwrapped; did you mean to use '!' or '?'?
Unfortunately, this fails. The compiler seems to be complaining about something. Why cannot we just add these two numbers? After all, we are sure that the factorial of 3 is 6, so it seems that our operation should be possible.
The problem here lies in the fact that we are trying to add what to the compiler are two distinct type. The result of the factorial function is not of type Int but of type Int?. For the compiler these are two distinct types and they cannot be added to each other. We will see later why this is true. For now it is helpful to think that a number cannot be added to something that might or might not be a number. To be able to perform this addition we have to transform the optional value into a non optional one. We do this using the forced unwrapping operator !
factorial(3)! + 7 // 13
The meaning of the forced unwrapping operator is: “I know that this optional has a value, so please use it.” There is a problem though: while in this simple example we know for sure, most of the time, we actually do not know if an optional will have a value or not. Using forced unwrapping on a nil value will cause a runtime exception and a crash. We have to make sure that the optional has a value with an if statement before unwrapping it:
let result = factorial(3) if result != nil { result! + 7 } // 13
If and while statements support optional binding, which allows to check an optional and to extract its value as part of a single action. In this way, the forced unwrapping of the optional inside of the body of the statement is not necessary anymore. This is especially handy if we use the optional more than once in the body of the statement.
if let result = factorial(3) { result + 7 } // 13
Sometimes, when an optional has no value, we want to provide a default one instead. We can of course do this using an if statement or, more succinctly, the ternary operator:
let fact = factorial(-5) 5 + (fact != nil ? fact! : 0) // 5
The expression between parentheses means “if fact has a value, use it, otherwise use 0.” (Beware that in this case the question mark is not an optional operator, but is part of the syntax of the ternary operator). The nil coalescing operator is a way to shorten this expression:
5 + (fact ?? 0) // 5
Optionals in structures and classes: optional chaining
Optional chaining on properties
Optionals are not only used as return values in functions, but can also be used for variables and properties of structures and classes. We use this to indicate a variable or property that does not hold any value. As an example, let’s create a structure to hold a person information for a city library, with an associated library card that will hold the list of books the person borrows.
class Person { var libraryCard: LibraryCard? } class LibraryCard { var numberOfBorrowedBooks = 0 }
The libraryCard property is an optional, because not everybody has a subscription to the library. We now want to print how many books a person has borrowed in the past. To get to the numberOfBorrowedBooks property, though, we have to traverse the optional libraryCard property of the Person class, which might be nil. We can of course use an optional binding on libraryCard and, if not nil, access the the numberOfBorrowedBooks property of the unwrapped value. Swift though has an alternative mechanism that allows us to directly go through the optional to the value we want, without the use of an optional binding. This is called optional chaining and is done using a ? after the optional property:
let john = Person() if let numberOfBorrowedBooks = john.libraryCard?.numberOfBorrowedBooks { println("John has borrowed \(numberOfBorrowedBooks) books") } else { println("John does not have a library card") } // prints "John does not have a library card"
In this case the ? has a different meaning that it had when we put it after a type. The latter meant “this value might not exist”. Used at the end of a variable or a property, a ? means instead “If it has a value, access this other property, otherwise return nil”. So if libraryCard is not nil we access its numberOfBorrowedBooks property directly. This is different from using a !, which would force the optional to unwrap and cause a crash in case it finds a nil.
Since accessing the numberOfBorrowedBooks property might fail, the value returned by the optional chaining is an optional even if the original property is not. In this case, the numberOfBorrowedBooks property has type Int, but the value returned by me.libraryCard?. numberOfBorrowedBooks has type Int?.
It is also possible to try to set a property through optional chaining. While an assignment normally would not have a return type, attempting to set a property through an optional chaining returns a value of type Void?. This allows to check if the assignment was successful :
john.libraryCard = nil if (john.libraryCard?.numberOfBorrowedBooks = 1) != nil { println("The assignment was successful") } else { println("It was not possible to assign a new identifier") } // "It was not possible to assign a new identifier"
Optional chaining on methods
Optional chaining can also be used to call methods on an optional. Let’s now expand our classes to include a list of borrowed books:
class LibraryCard { var borrowedBooks = [Book]() var numberOfBorrowedBooks: Int { get { return borrowedBooks.count } } func addBook(book: Book) { borrowedBooks.append(book) } } class Book { let title: String init(title: String) { self.title = title } }
Like in the case of the assignment, the addBook method has a Void return type, but through the optional chaining this will become Void?, allowing us to check for the success of the method call.
let book = Book(title: "Moby Dick") if (john.libraryCard?.addBook(book)) != nil { println("John has borrowed \(book.title)") } else { println("John has not a library card and cannot borrow books") } // prints "John has not a library card and cannot borrow books"
Multiple levels of chaining
Optional chaining can be concatenated to go down multiple levels of optionals. Let’s add a property to LibraryCard to retrieve the last book a person has borrowed:
class LibraryCard { var borrowedBooks = [Book]() var numberOfBorrowedBooks: Int { get { return borrowedBooks.count } } var lastBorrowedBook: Book? { return borrowedBooks.last } func addBook(book: Book) { borrowedBooks.append(book) } }
We can now use multiple levels of chaining to fetch the title of the last book John borrowed:
john.libraryCard = LibraryCard() let book = Book(title: "Moby Dick") john.libraryCard?.addBook(book) if let bookTitle = john.libraryCard?.lastBorrowedBook?.title { println("The last book John has borrowed is \(book.title)") } else { println("John has not borrowed any books") } // prints "The last book John has borrowed is Moby Dick"
As we have seen, even if the type returned by a property or a method is not optional, optional chaining will make it so. If the type is already optional though, it will not make it more optional. In this case, we have two levels of chaining, but the return type is still String?, not String?? (if you are wondering if this is possible, yes, it is. More on this later).
Finally, optional chaining can be used on subscripts as well. Everything that has been said for properties and methods applies to subscript too.
Optional chaining on optional protocol requirements
Until now we have seen the use of optionals for things that might not return a value. Optional chaining can be also used for properties and methods that might not exist. This is the case with optional protocol requirements. When defining a protocol, it is possible to specify some methods or properties as optional. This means that the classes that conform to the protocol are not required to implement them. Thus, when you are accessing these properties or methods of a protocol type, you cannot be sure that a conforming class has an implementation for them. For this reason the use of optional chaining is required.
Let’s assume we are making an RPG game, which includes wizards. A wizard can sometimes have a familiar creature, which can be a simple animal or a more powerful magical creature. Some familiar creatures can give the wizard an extra spell to cast. We can express this with a protocol:
class Spell: NSObject { } @objc protocol Familiar { optional func familiarSpell() -> Spell }
(Note: the protocol is marked with the @objc keyword because this is the only way to declare optional methods or properties in protocols in the current implementation of Swift. The Spell class inherits from NSObject instead of being a pure Swift class because the return value of optional protocol requirements needs to be Objective-C compatible).
We can now implement the Wizard class, with a method returning the available spells to cast:
class Wizard { var familiar: Familiar? var spells = [Spell]() func availableSpells() -> [Spell] { if let familiarSpell = familiar?.familiarSpell?() { return spells + [familiarSpell] } return spells } }
Here optional chaining is used in two different ways. The first one we have already seen. The wizard might not have a familiar, so the familiar property is an optional. The second one instead checks if the familiarSpell method is present. Notice that the ? is placed before the parentheses in the method call and not after. The latter would check if the returned value existed, while in this case we are checking for the existence of the method itself.
Avoiding the checks for nil: implicitly unwrapped optionals
As we have seen, optionals add to our code a lot of question and exclamation marks, if statements and optional bindings, which end to make it harder to read. This is one of the trade offs of optionals. There are some specific cases though, where we know that after an optional property will have a value, it will never be nil again. In these cases all the checks are not needed. Even forced unwrapping is not, since we know that the optional will always have a value from some point on, thus making it not really an optional anymore.
For this cases, we can declare an optional as implicitly unwrapped. We do so by placing a ! after its type instead of a question mark. This will allow the optional to start with a nil value when a valid value cannot be provided yet, while allowing us to use it as if it was not an optional (without special operators and checks). There are a few cases where this is needed.
Unowned references in reference cycles
When two objects hold a reference to each other, we have to avoid creating strong reference cycles under ARC, or the two object will never be removed from memory. There are three specific cases in which this cycles can exist.
In the first case the two objects can both have a nil reference to the other. This case is solved by declaring both the references as optionals and marking one of the two references as weak. For example, a Person and an Apartment object can have a reference cycle, but they can exist independently from each other:
class Person { var apartment: Apartment? } class Apartment { weak var tenant: Person? }
In the second case one of the two references always needs to have a value, because the existence of the referenced object depends on the existence of another one. Since this property is not an optional, it cannot be marked as weak, since weak references are set to nil by ARC when the referenced object is removed from memory. On the other hand, the reference in the other object cannot be weak either, because it is needed to keep the dependent object in memory. This case is solved in Swift by making the first reference as optional and marking the second reference as unowned, which makes it behave like a weak reference from the point of view of ARC, without being set to nil. For example, a customer of a bank might have or not have a credit card. A credit card, though, needs to always have an associated customer.
class Customer { var card: CreditCard? } class CreditCard { unowned let owner: Customer init(owner: Customer) { self.owner = owner } }
In the remaining case both references always need to have a value. In this situation, one of the two objects gets created in the initializer of the other one, which passes itself as a parameter to the initializer of the second one. This guarantees that both references are initialized properly. Here there is a problem, though: Swift does not allow to reference self until the object is completely initialized. To be completely initialized, though, the first object needs to create an instance of the second, passing self as a parameter, which is forbidden. This is where implicitly unwrapped optionals come to the rescue. The first reference is made an implicitly unwrapped optional, which allows it to be initialized to nil temporarily, while the second instance gets created.
class Country { var capitalCity: City! init() { self.capitalCity = City(country: self) } } class City { unowned let country: Country init(country: Country) { self.country = country } }
Initialization of IBOutlets
Another common scenario for implicitly unwrapped optionals are outlets to objects coming from a storyboard or a xib file. When views or view controllers are initialized from an interface builder file, their outlets cannot be connected yet. They will only be connected after initialization, so they need to be optional. When any other code in the class is called after initialization, though, these outlets are guaranteed to be connected. This is why IBOutlets are always declared as implicitly unwrapped optionals.
Failable initializers
When the initialization of an object fails, it should return nil as soon as possible. By definition, though, not all the properties will have been initialized by that point and Swift does not allow an init method to return until all properties are initialized. Implicitly unwrapped optionals solve this problem (more on this later).
A note on implicitly unwrapped optionals
Implicitly unwrapped optionals are dangerous and should be used only when you are sure of what you are doing. The reason is that they bypass all the compiler checks so they have a high potential of generating a runtime exception. As said, they are intended for specific cases where you are sure that the value will always exist after initialization, not requiring it to be unwrapped every time. This is not always so easy to know. It is easy to fall into the temptation to use implicitly unwrapped optionals for cases that do not fall under this rule, since they might seem very convenient. Doing this, though, defeats the whole point of optionals. When in doubt, use a non optional value if you can or a normal optional instead.
Asking an object for its type: downcasting
When we work with different classes that inherit from a single superclass, we might need sometimes to access properties or method of a specific subclass. To be able to do this, we have to downcast an object from its generic superclass to the more specific subclass. Swift offers two operators for this: as and its optional version as?. The first one is used when we are already sure of the type of an object. Many times, though, we do not know the specific subclass. Using the as operator is the same as forcing the unwrapping of an optional, it causes a runtime exception in case of failure.
As an example, let’s go back to our library. Libraries nowadays rent not only books, but also movies, so we have to make a distinction between the two
class LibraryItem { let title: String init(title: String) { self.title = title } } class Book: LibraryItem { let author: String init(title: String, author: String) { self.author = author super.init(title: title) } } class Movie: LibraryItem { let director: String init(title: String, director: String) { self.director = director super.init(title: title) } }
We can put the catalog of our library inside an array containing all the items. When we want to print this catalog, we have to check if each item is either a book or a movie. We do this with the as? operator, which returns an optional that needs to be checked:
let catalog = [ Book(title: "Moby Dick", author: "Herman Melville"), Movie(title: "2001: A Space Odissey", director: "Stanley Kubrick") ] for item in catalog { if let book = item as? Book { println("Book: \(book.title), written by \(book.author)") } else if let movie = item as? Movie { println("Movie: \(movie.title), directed by \(movie.director)") } } // "Book: Moby Dick, written by Herman Melville" // "Movie: 2001: A Space Odissey, directed by Stanley Kubrick"
The types of the book and movie objects in this example are Book? and Movie? respectively.
When a value cannot be initialized: failable initializers
Sometimes it is useful to have the initialization of a structure, class or enumeration fail to prevent the creation of objects with the wrong initialization parameters. Swift offers the opportunity to mark an initializer as failable, meaning that initialization of an object might return nil if the initialization fails. You do so by placing a ? after the init keyword for the initializer, before the method parentheses.
As an example, let’s assume that we have a structure to represent animals, and we want to prevent that values are initialized without a valid species. A non optional parameter in the initializer already does part of the check, not allowing nil to be passed, but we also want to make sure that the passed string is not empty:
struct Animal { let species: String init?(species: String) { if species.isEmpty { return nil } self.species = species } }
Since the initializer could fail, it will need to be checked, for example with an optional binding:
if let giraffe = Animal(species: "Giraffe") { println("A new \(giraffe.species) was born!") } // Prints "A new Giraffe was born!”
If we want to define Animal as a class instead of a structure, this does not work and there is one slight change we have to make. In a class, a failable initializer must provide a value for each property before triggering a failure. But the species property cannot be initialized until after the check that triggers the failure. The solution is to make the species property an implicitly unwrapped optional:
class Animal { let species: String! init?(species: String) { if species.isEmpty { return nil } self.species = species } }
In this new definition, the only difference is the ! at the end of the type of the species property.
How optionals work under the hood
We have seen all the various operators and uses where optionals appear when working with Swift. At a first sight, optionals might seem like some magic the compiler performs to transform any type into an optional, allowing us to use nil values where they would not normally be supported (e.g. with integers). Many languages get away with using 0 as a value for nil for reference types, since references are usually numeric memory addresses and 0 is not a valid address. This is not possible with simple types like integers, floating point numbers, characters and booleans, where the value 0 is usually an acceptable value (for booleans, 0 usually means false in these languages) . So how does Swift get away with this?
It turns out that optionals are not so obscure. They are implemented using other standard language features and we can understand how they work under the hood. It is useful to understand how they work to prevent some problems and to be able to use optionals more effectively. Let’s see how easily these underlying implementation details come to the surface and why it is worth understanding them.
Let’s say we create a dictionary with the capitals of different countries:
let capitals = ["Italy": "Rome", "France": "Paris", "Spain": “Madrid"]
Now we have a list of countries, for which we want to get the capitals:
let countries = ["Italy", "Spain", "Germany"]
We can use the map function on the countries array to extract the corresponding capital of each country from the capitals dictionary. Our array of countries contains Germany, which is a country not included in the dictionary of capitals, but this is not a problem: a key lookup in a dictionary returns an optional, so when a key is not found, nil is returned.
let result = countries.map { capitals[$0] } println(result) // Prints "[Optional("Rome"), Optional("Madrid"), nil]”
As expected the last value is a nil and other values are printed as optional, which sure is convenient. This is not a surprise of course, our original array was of type [String] and a lookup in a dictionary returns an optional, so our result array is of type [String?]. So far so good. Let’s extract the last value of the result array, which is nil.
println(result.last) // Prints "Optional(nil)"
Wait, what is going on here? We expected nil, but we actually got an Optional(nil). What does that even mean? A nil that could also be nil? Let’s look at how the last property of an array is declared in the Swift standard library:
var last: T? { get }
The type of last is the optional of the type contained in the array. But our array already contains values of type String?, so the last property returns a value of type String??.
What is this double optional type? Let’s try to see if we can define it ourselves directly:
let nested: Int?? = 3 println(nested) // Prints "Optional(Optional(4))" let doublyNested: Int??? = 7 println(doublyNested) // Prints "Optional(Optional(Optional(7)))"
Indeed it seems that we can nest optionals inside other optionals as deep as we want. Let’s put aside the semantics of this, how is this possible from a pure syntactical point of view? At the end of the Swift Programming Language guide from Apple, there is a chapter on the language reference, which many people probably skipped (I was one of those). In that chapter, the section dedicated to the Optional Type states:
“The type Optional<T> is an enumeration with two cases, None and Some(T), which are used to represent values that may or may not be present. Any type can be explicitly declared to be (or implicitly converted to) an optional type.”
This solves the mystery: optionals are in reality a generic enumeration that has two cases, one for the value and one for the absence of the value. The various operators we have seen are just syntactic sugar around this enumeration. Actually you can even define most of them yourself using operator overloading, if you want.
This is why we cannot, for example add an Int and an Int?: the first one is an integer, while the second one is an enumeration, which is a clear type mismatch. More in general, any optional type is a complete different type compared to its non optional counterpart. This is also why we talk about unwrapping an optional: the value is contained inside an enumeration, so we have to extract it before using it.
This allows us to use some features of enumerations to deal with optionals. For example, it happens sometimes that some operation can be performed only when all the values of different optionals exist. This leads to some nesting if we are using optional bindings:
let a: Int? = 1 let b: Int? = 2 let c: Int? = 5 if let a = a { if let b = b { if let c = c { println("The sum of the three numbers is \(a + b + c)") } else { println("The operation could not be performed") } } else { println("The operation could not be performed") } } else { println("The operation could not be performed") } // Prints "The sum of the three numbers is 8"
Note that in this example the three constants a, b, and c are assigned integers just for the sake of simplicity. In a real life situation those values could come from functions that might return nil (and might be of different types as well, of course).
If we want the sum of all three of them and to fail otherwise, we have to first check each one of them separately, since optional bindings allow only one binding at a time (maybe some future versions of Swift will allow multiple bindings at the same time). This also makes us repeat the code we want to execute when each one of the test fails. Not really the most readable piece of code.
Relying on the fact that optionals are enumerations behind the scenes, we can compress them in a single switch statement:
switch (a, b, c) { case let (.Some(a), .Some(b), .Some(c)): println("The sum of the three numbers is \(a + b + c)") default: println("The operation could not be performed") } // Prints "The sum of the three numbers is 8"
Here we are checking the three optionals switching on a tuple made of all three of them. The first case matches the case where they all contain a value in their .Some field. If any of these does not have a value, it falls into the default case. This can also get more complicated with more cases if we want, but it still avoids nesting and repetition.
The Optional<T> type also defines a map function. This returns the value of the closure passed as a parameter if the optional has a value, and nil otherwise. This can be useful whenever we want to apply some function to an optional without checking for it to be nil, delegating the control to other parts of the code. For example, let’s assume we have a function that calculates the square of an integer:
func square (x: Int) -> Int { return x * x }
By definition this function works only with integers and does not accept optionals. If we want to calculate the square of an Int?, we have to first check for it to be non nil and then apply the square function to its unwrapped value. Or we can use the map function of Optional<T>, which will return nil in case the optional is nil:
let optionalNumber: Int? = nil optionalNumber.map { square($0) } // nil
In practice, the map function allows us to apply to optionals any function that would not normally accept optionals as parameters.
What is the point of having optionals in Swift?
Although optionals are a new concept for many developers, they do not solve a new problem. Dealing with non existing values is a problem that has existed for long time. Many languages, like Objective-C, solved this problem by using nil values for references. Although we still use nil values in Swift, optionals approach the problem in a different way. Apart from the fact that is possible to use nil values with simple what benefits do optionals bring to the table?
One of the first advantages of optionals is that in Swift it is always clear from the type of a value if it can be nil or not.
In many other languages there is no such a guarantee. Some functions might return nil values, some never will, some others might use some special values instead (for example -1). Some function parameters can be nil, some others need to have a value. This is never clear from a declaration, though. To know for sure you have to check the code or the documentation, or guess and hope that it will cause unexpected problems. Many times you don’t have access to the source and the documentation might not even mention it. I have found myself many times reading some documentation, even from Apple, wondering whether nil values were acceptable or not.
In Swift there is no such a problem. If a type of a return value or a parameter is not declared as optional, we are sure that a nil value will never be present. To be able to use nil we have explicitly allow it. This saves us from a lot of mental baggage that might accumulate in our mind while developing. As we write our code, we have to keep in mind wether a value could be nil or not. In Objective-C for example, nil values propagate throughout our code base, ending up in unexpected places. Swift forces us to deal with nil values as soon as they surface in our code, making us dispose of them as soon as they appear. This makes sure they will not make their way into other parts of our code.
A second advantage is that the compiler can do many of the checks for us. Many times, even if we try to think about all the possible edge cases for our code, some nil value is going to slip out. We are only humans and we cannot keep all this information in mind all the time. We can try to guard us with assertions, but they go only that far. The compiler, though, can stop us as soon as we make a mistake. I know it can feel annoying to have your code not compile because the compiler is complaining about some optional that is assigned to a non optional value. But if you think about it, it could have caused a very hard to track bug later that would have required, in the end, more time to fix.
Swift is a highly opinionated language and some people will disagree with those opinions. Optionals are one of those. Coming from Objective-C, I myself thought at first that it would have been annoying to check for nil values all the time. In the end, though, I find myself appreciating the value that optionals offer. They need a bit more though beforehand, but you can get used to it pretty quickly. In my opinion the benefits outweigh the initial annoyance.
Reading comments and blog posts, many people seem to hate optionals, but I think most of the times this comes from a poor understanding. When you know exactly why some values might be optional and how to deal with them, a lot of the frustration goes away. You can still bypass the compiler complaints by explicitly unwrapping optionals without checking the value. If you know the implications of what you are doing, this is fine and I do that too, sometimes. The point here is that when you understand how optionals work and why, you have the tools to better reason about your code and take decisions. As in many things, this requires understanding the benefits and the pitfalls of such decisions. This understanding allows you to take routes that might seem dangerous at first, but are much safer than they look.
Enjoyed this guide? Here you can find a more updated version.
Matteo has been developing apps for iOS since 2008. He has been teaching iOS development best practices to hundreds of students since 2015 and he is the developer of Vulcan, a macOS app to generate SwiftUI code. Before that he was a freelance iOS developer for small and big clients, including TomTom, Squla, Siilo, and Layar. Matteo got a master’s degree in computer science and computational logic at the University of Turin. In his spare time he dances and teaches tango.
very nice guide.
love your blog. great examples.
“Some types of familiar can give the wizard an extra spell to cast.” I am confused by this sentence?
What do you find confusing? Maybe I should have not used the word type here, since it’s a programming word as well as a real world one. You can rephrase it removing that word, like “some familiar creatures can give the wizard an extra spell to cast”. Does this work better?
Let me know, so I’ll rephrase it in the article.
Adding in the word “creatures” makes it make more sense I think… When I read it before, I thought, “What is ‘a familiar’?”
Ah, I see what is confusing then. Thanks!
let capitalCity: City! should be var capitalCity: City!
Fixed it. Thanks!
Am new in programming. Started with Swift and just picking. Love your article. Tremendously helpful. These free articles are currently my only hope of learning since I can’t afford paid product yet from this corner of Africa. Can I send mail from time to time to ask for help? Would be highly honored. Thanks
Commendable work!!
I was struggling with the optional related compiler errors in Xcode, your blog helped me a lot to learn the purpose and the concept of optionals in depth.
Extensive, clear, efficient. Thx
FABULOUS!
I do understand how optionals work and why…and I still think this is over-engineering at its best. I get why they want a sentinel value — but why didn’t they just do a “unassigned” or some other keyword that you could check against? They could then handle the wrapper object all under the hood. Way to many hoops to jump through with optionals. And they still don’t guarantee that you won’t pass a nil constant if you mess up. Total mess all for the sake of making sure that you never get confused over a int ==0 vs int == no value.
Amazing article! The best one yet regarding optionals. I could never imagine this pieced of code:
switch (a, b, c) {
case let (.Some(a), .Some(b), .Some(c)):
print(“The sum of the three numbers is (a + b + c)”)
default:
print(“The operation could not be performed”)
}
// Prints “The sum of the three numbers is 8”
True eye opener!
Thank you!