Protocols - Learning Swift Programming (2015)

Learning Swift Programming (2015)

8. Protocols

Protocols are at the heart of the iOS architecture; they are first-class paradigms, right up there with classes and structs. They hold a special place because they are the backbone of design patterns such as delegates. Delegates are heavily used in iOS for notifying the programmer when application, UI, and other events happen. You can use a delegate to send a message to everyone who conforms to that protocol. When you use a protocol and all of its offerings, it is called conforming to the protocol.

Protocols themselves don’t have any implementation at all—that is, you don’t really write code in protocols that does stuff. You can use protocols as a checklist to say, “I need you to write the following methods if you want this thing to work.” Protocols describe what must be implemented and what that implementation should look like. You can use protocols with classes, structures, and enumerations. When a class, struct, or enum provides the functionality described in the protocol, you can then say that it is conforming to the protocol.

Writing Your First Protocol

To create a protocol, you start with the keyword protocol and then give it a name, followed by a pair of curly brackets. A basic protocol would look like this:

protocol MyProtocol {
}

You might notice that this newly created protocol is completely empty. Although it is empty, it is valid. The protocol doesn’t currently have any functions that it wants you to conform to, but you can provide an implementation of it already. You’ll create a class that conforms to MyProtocol. It won’t be hard to conform to it because it doesn’t have any functions to conform to yet. It’s like if someone gave me a blank shopping list: I would drive to the supermarket and, when I got there, I would just turn around, because there is nothing to get. Here is the implementation, using a class.

class MyClass:MyProtocol {
}

The way you tell this class to conform to the protocol is the same way that you tell the class to inherit from another class: You just use the colon followed by the name of the protocol you want implemented. The protocol definition goes inside the curly brackets.

Now you can create an implementation of this protocol. This protocol does not create any requirements, so the class implementation will be just as sparse as the protocol:

protocol MyProtocol {

}

class MyClass:MyProtocol {

}

If you run this in the playground, you will notice that there are no errors. However, if you add the requirement of a property to the protocol, like this, then the class will need to implement it as well:

protocol MyProtocol {
var someProp:String { get set }
}

class MyClass:MyProtocol {

}

Now you’ll get an error:

:6:1: error: type 'MyClass' does not conform to protocol 'MyProtocol'
class MyClass:MyProtocol {
^
:3:9: note: protocol requires property 'someProp' with type 'String'
var someProp:String { get set }
^

What happened? Now you are saying that the protocol has a requirement: A property called someProp must be a getter and a setter. You can fix this error by giving the class the property that the protocol requires. Here’s how you do it:

protocol MyProtocol {
var someProp:String { get set }
}

class MyClass:MyProtocol {
var someProp:String = ""
}

When this code runs, the error goes away. You are now strictly adhering to the requirements of the protocol. That is, you are now conforming to the protocol.


Note

Notice the words get and set. In this case, you are saying that someProp can be read (that’s get) and written to (that’s set).


Properties

This is a good time to talk briefly about getters and setters in Swift. In Swift, you can have a property of a class that is a getter or a setter or both. To see how this works, you’ll create a class called Human, and then you’ll see what it means to get and set properties of that class:

class Human {
var eyeColor = "#00FF00"
var heightInInches = 68
var hairLengthInCM = 2.54
var name = "Skip"
}

This class has four properties. You may or may not want all of these properties to be able to be rewritten. For example, once the eye color is set, you might only want that to be able to be read and not written to. There are also other details you can get from these properties being set. For example, you could say that this person’s height in a string would be "medium". You can use computed properties for this.

The types of variables you have been writing up to this point are called stored properties. You can either have a variable stored property or a constant stored property. You know from Chapter 1, “Getting Your Feet Wet,” that you use the keyword var to signify a variable stored property and the keyword let to signify a constant stored property. You can define a default value of a stored property when you declare it in a class, a struct, or an enum. You did this in the Human class with all the properties. You can also change the default value at initialization.

In addition to stored properties, there are, as mentioned earlier, computed properties. Computed properties are not stored values; they provide instructions to Swift on how to compute the value of a property. They are used to set and get other stored properties indirectly. You can provide a getter and optionally a setter, as shown here:

class Human {
var eyeColor = "#00FF00"
var heightInInches = 68
var hairLengthInCM = 2.54
var heightDescription:String {
get {
if heightInInches >= 92 {
return "tall"
} else if heightInInches <= 30 {
return "short"
} else {
return "medium"
}
}
}
}

var human = Human()
println(human.heightDescription) // medium

Here you create a height description, which describes the height of a human, in inches. You are basing this height on the heightInInches property of the Human. You can create a setter as well if you want to set the height of the person by using a description. Ideally, you would create an enum to describe the different heights available, but for this example you can just use Strings, like this:

class Human {
var eyeColor = "#00FF00"
var heightInInches = 68
var hairLengthInCM = 2.54
var heightDescription:String {
get {
if heightInInches >= 92 {
return "tall"
} else if heightInInches <= 50 {
return "short"
} else {
return "medium"
}
}
set (newHeightDescription) {
if newHeightDescription == "short" {
heightInInches = 50
} else if newHeightDescription == "tall" {
heightInInches = 92
} else if newHeightDescription == "medium" {
heightInInches = 60
}
}
}
}

var human = Human()
println(human.heightDescription)
human.heightDescription = "short"
println(human.heightInInches)

Now you can set the height of the person in inches by using a String. You can now use the equal sign on that computed property. You can see this with heightDescription, where you use the equal sign to set the height description as a String, which in turn sets the height of the human, in inches. Although it isn’t the most accurate way of setting a person, it might be helpful in a game where you are creating people on the fly, and you want to create 100 tall people. Instead of hard-coding their heights, you can just set them to be "tall".

In the next example, you set the height from the parameter that was passed in: newHeightDescription. This is optional as you could rewrite this example and just use the default parameter newValue. Here you rewrite just the setter portion of the last example to use a parameter named newValue instead of providing a named parameter yourself:

set {
if newValue == "short" {
heightInInches = 50
} else if newValue == "tall" {
heightInInches = 92
} else if newValue == "medium" {
heightInInches = 60
}
}

Notice that you don’t have to declare a variable here. Instead, you use a variable, called newValue, that is available to you in all setters. Many languages with getters and setters use the same variable name newValue or valueor something similar for setters.

Notice that you cannot create read-only stored properties directly. Here’s a little trick for creating read-only stored properties: Create a private stored property and a read-only computed property, and you have yourself a read-only stored property. Here is an example of a read-only stored property:

class Human {
private var _name = "Skip"
var name:String {
get {
return _name
}
}
}
var human = Human()
println(human.name)
human.name = "Jack"

Now you have a property that is being stored, and you have made it read-only. You use the underscore to denote a private variable, but this is only aesthetic so that you can use the variable name name twice. This tells the reader that these are the same variable.

The lazy Variable

The last topic in our little properties discussion is the lazy variable. This variable sits on the couch all day and does absolutely nothing. It’s always mooching off you and never cleans his dishes. Actually, lazy is pretty handy. You use it to create a variable that is not evaluated until it is actually used. You can declare this variable with the keyword lazy. This type of variable is useful when you won’t have the initial value of this property until after initialization. Rather than throw an error, you can just tell Swift that you will have the value when you need it, but you just don’t have it right now. Here is an example of using the lazy keyword, which you don’t have at initialization but will have ready when it is needed (it runs once when it’s first accessed):

class Namer {
var name:String {
get {
//url request for name
return "Jack"
}
}
}

class Human {
lazy var namer:Namer = Namer()
}
var human = Human() // Namer hasn't been initialized yet.
println(human.namer.name) // Now namer has been initialized

In this example, it is possible that the Namer class’s name property won’t be ready on initialization. Swift is okay with this, as long as you use the lazy keyword to inform Swift that it shouldn’t try to grab the value from the nameclass yet.

And now back to your regularly scheduled program on protocols.

Animizable and Humanizable

In this section, you will make a protocol for the creation of any animal, and call it Animizable. This protocol will make sure that anytime someone creates an animal, it will have the proper properties and methods. A lot of times, the names of protocols have able at the end. These are some of the Swift standard protocols you will commonly come across:

Equatable: You must overload the == operator. This allows you to test your type for equality.

Comparable: You must overload the <, >, <=, and >= operators, which will allow you to compare your custom type.

Printable: You must declare a property of type String called description, which will provide a String-based representation of the type.

Methods

You can use a protocol to declare a method requirement. In this case, the adopting implementation must use the methods listed in the protocol in order to conform to it. Here is an example of this situation with your new Animizable protocol:

enum Food:String {
case Meat = "meat"
case Veggies = "veggies"
case Other = "something else"
}

protocol Animizable {
var type:String { get }
func eat(quantityInPounds:Double, what:Food)
}

class Animal:Animizable {
var type = ""
func eat(quantityInPounds:Double, what:Food){
println("I am \(type) and I am eating \(quantityInPounds) pounds of
\(what.toRaw()).")
}
}

var human = Animal()
human.type = "human"
human.eat(2,what: .Meat)

Here you are creating an Animizable protocol, which requires that you add a property type and a method called eat. The implementation of the method must have the same parameters as the protocol’s definition of the method. If you want Animizable to have a type method, then you need to write that in the protocol. You could update the Animizable protocol to require a type method called lbsToKg as a convenience method to convert pounds to kilograms. You can update your code as follows:

protocol Animizable {
var type:String { get }
class func lbsToKg(lbs:Double) -> Double
func eat(quantityInPounds:Double, what:Food)
}

class Animal:Animizable {
var type = ""
class func lbsToKg(lbs:Double) -> Double {
return lbs * 0.453592
}
func eat(quantityInPounds:Double, what:Food){
println("I am \(type) and I am eating \(quantityInPounds) pounds of
\(what.toRaw()).")
}
}

Now the protocol requires a type method. You must implement this method when creating your Animal class.

This also goes for mutating methods as well: If you want a function to be mutating, you must declare it in the protocol. The implementation of that protocol must then create a mutating method. Mutating is used only for enums and structs. If you implement a protocol that requires a mutating method using a class, then you do not need to write the mutating keyword.

Delegation

Delegation is one of the most powerful features of protocols. Delegation is not special to Swift or Objective-C. It is a design pattern, a reusable solution to a common problem within a certain context. A friend of mine described delegation best without even knowing it. He said, “Doesn’t a protocol allow you to send messages to anyone who implements that protocol?” Sort of. If you create a new iOS project, the first thing you will most likely see is the AppDelegate, which notifies you when certain things happen. For example, in AppDelegate there is a method called applicationWillTerminate. This method gets called when the application is about to be shut down. It can be called because it adopts UIApplicationDelegate. Let’s look at how the delegate design pattern works.

Say that you create a protocol called Humanizable, where things will happen to Human (which adopts Humanizable), and you want to notify others of those things:

protocol Humanizable {
var name:String { get set }
func eat(quantity:Int)
func play(game:String)
func sleep()
}

You now have a protocol, which can be adopted by any Human. You then create a HumanizableDelegate protocol that can be adopted in order to be updated with changes to the Human. Each function will get an instance of the Human that is doing the updating:

protocol HumanizableDelegate {
func didStartEating(human:Humanizable)
func didFinishEating(human:Humanizable)
func didStartPlaying(human:Humanizable)
func didFinishPlaying(human:Humanizable)
func didStartSleeping(human:Humanizable)
func didFinishSleeping(human:Humanizable)
}

You can now keep track of changes to the Human. You next create a class that conforms to the Humanizable protocol and will have a delegate to do the informing:

class Human:Humanizable {
var name:String
init(name:String) {
self.name = name
}

var delegate:HumanizableDelegate?

func eat(quantity:Int) {
delegate?.didStartEating(self)
println("Eating \(quantity) pounds of food, yum yum yum")
delegate?.didFinishEating(self)
}

func play(game:String) {
delegate?.didStartPlaying(self)
println("I am playing \(game)! So much fun.")
delegate?.didFinishPlaying(self)
}

func sleep() {
delegate?.didStartSleeping(self)
println("I am sleeping now. Shhhh.")
delegate?.didFinishSleeping(self)
}
}

You are now conforming to the Human class. Our Human class implements the actual functionality of the eat, play, and sleep methods of Humanizable. When the instance of the human sleeps we tell our delegate when we have started sleeping and when we have stopped. Now all we have to do is make a human watcher to keep track of all the stuff happening with our human. This class will conform to HumanizableDelegate and truly get informed of changes.

class HumanWatcher:HumanizableDelegate {
func didStartEating(human:Humanizable){
println("We just were informed that \(human.name) started eating")
}
func didFinishEating(human:Humanizable){
println("We just were informed that \(human.name) finished eating")
}
func didStartPlaying(human:Humanizable){
println("We just were informed that \(human.name) started playing")
}
func didFinishPlaying(human:Humanizable){
println("We just were informed that \(human.name) finished playing")
}
func didStartSleeping(human:Humanizable){
println("We just were informed that \(human.name) started sleeping")
}
func didFinishSleeping(human:Humanizable){
println("We just were informed that \(human.name) finished sleeping")
}
}

Now you can be completely informed of the Human’s activity and do something about it. Even if watching the Human means printing out lines to the console, that’s what you’ll do. The last thing you need to do is to create the actual instances of the Humans and their Human watchers. The fact that you are using protocols means you can guarantee that the Human will have certain methods. You do not have to worry about those methods not being implemented. Let’s create the protocol design pattern using our new human “Jeff”:

let humanWatcher = HumanWatcher()
let human = Human(name:"Jeff")
human.delegate = humanWatcher
human.play("marbles")
human.sleep()
human.eat(5)

We just were informed that Jeff started playing
I am playing marbles! So much fun.
We just were informed that Jeff finished playing
We just were informed that Jeff started sleeping
I am sleeping now. Shhhh.
We just were informed that Jeff finished sleeping
We just were informed that Jeff started eating
Eating 5 pounds of food, yum yum yum
We just were informed that Jeff finished eating

With the delegate pattern, the delegate of an instance can notify you of things happening in that instance of a class.

Protocols as Types

You know that protocols don’t implement any functionality themselves, but that doesn’t stop you from using them as parameters or return types in methods. This is where protocols can become extremely powerful. You can use them as a type for a variable or constant, or for arrays and dictionaries.

Here is a protocol that can work for anything that you would like to make walkable:

protocol Walkable {
var name:String { get set }
func walk(#numOfSteps:Int)
}

Humans can walk and animals can walk, among other actions. Here’s how you can make a human that can walk:

class Human:Walkable {
var name = "John"
func walk(#numOfSteps:Int) {
println("Human is walking \(numOfSteps) steps")
}
}
func runWalker(walker:Walkable) {
walker.walk(numOfSteps:10)
}
var somethingThatWalks = Human()
runWalker(somethingThatWalks)

In this example you create a Human class that takes anything that can walk. This works because it adopts the Walkable protocol. You create a top-level function that will walk any Walkable. Notice that the parameter that the runWalker function takes is Walkable. This means anything that adopts the protocol Walkable can be passed in. This gives you a lot of flexibility because now you just call walk on whatever is passed in. You know that what is passed in will have that function available because it adopts Walkable.

Protocols in Collections

Protocols can be used as types, so it shouldn’t be a surprise that a protocol can also be used as the type of a collection. Think about the case of the Walkable class from the previous section. Say that you want to create something else that can walk, such as a dog. Here’s what you do:

class Dog:Walkable {
var name = "Penny"
func walk(#numOfSteps:Int) {
println("The dog is walking \(numOfSteps) steps")
}
}

let dog = Dog()
let human = Human()
var walkers = [Walkable]()
walkers.append(dog)
walkers.append(human)
for walker in walkers {
walker.walk(numOfSteps:10)
}

Here you have a Dog and a Human, and they are both Walkable. You also have an array that is strictly typed for anything that is Walkable. Because the array takes anything that adopts Walkable, you can append the Dog and the Human to the array, and it works just fine. You can imagine that if you took an even more generic protocol, such as BooleanType, you could make a very wide-ranging collection.

Protocol Inheritance

You can very easily make protocols inherit other protocols, which will add the requirements on top of one another. To see how this works, in this section, you’ll create two other protocols: Runnable and Doggable. Runnablewill add one more function requirement: run(). Doggable will inherit Walkable and Runnable. Doggable will have the requirement of a bark function. Because it will implement Walkable and Runnable, it will also need to implement walk and run functions. Here’s how you create these protocols:

protocol Walkable {
func walk(#numOfSteps:Int)
}

protocol Runnable {
func run(#howFarInMiles:Float)
}

protocol Doggable: Walkable, Runnable {
func bark()
}

class Dog: Doggable {
func walk(#numOfSteps:Int) {
println("Dog will walk \(numOfSteps) steps")
}

func run(#howFarInMiles:Float) {
println("Dog will run \(howFarInMiles) miles")
}

func bark() {
println("Woof")
}
}

class FrenchDog:Dog {
override func bark() {
println("Le woof")
}
}

var dog = Dog()
var leDog = FrenchDog()
dog.bark() // Woof
leDog.bark() // Le woof

Here the new Doggable class inherits both the Runnable and Walkable protocols. If you were to not include walk or run or both in the Dog class, Swift would throw an error. The way to have a protocol inherit from other protocols is the same way you use in classes: You create a comma-separated list following the semicolon. You can make a protocol inherit from as many other protocols as you want.

We just talked about how to inherit multiple protocols from other protocols, but how do you adopt multiple protocols at once from a class, a struct, or an enum? We’ll look at that next.

Protocol Composition

Protocol composition is a fancy term for making a type adopt multiple protocols at once. If you need to make a type adopt multiple protocols, you use this syntax:

protocol<Protocol1, Protocol2>

Inside the angled brackets, you place the multiple protocols that you want the type to inherit. When you do this, you are creating a temporary local protocol that has the combined requirements of all the protocols you’ve listed.

Let’s make a sort of powered speaker that uses protocol composition:

import UIKit

protocol Powered {
var on:Bool { get set }
func turnOn()
func turnOff()
}
protocol Audible {
var volume:Float { get set }
func volumeUp()
func volumeDown()
}
class Speaker:NSObject, Powered,Audible {
var on:Bool = false
var volume:Float = 0.0
var maxVolume:Float = 10.0

func description() -> String {
return "Speaker: volume \(self.volume)"
}

func turnOn() {
if on {
println("already on")
}
on = true
println("Powered on")
}
func turnOff() {
if !on {
println("already off")
}
on = false
volume = 0.0
println("Powered off")
}
func volumeUp() {
if volume < maxVolume {
volume += 0.5
}
println("Volume turned up to \(volume)")
}
func volumeDown() {
if volume > 0 {
volume -= 0.5
}
println("Volume turned down to \(volume)")
}
}
var speakers:[protocol<Powered,Audible>] = []
for n in 1...10 {
speakers.append(Speaker())
}
func turnUpAllSpeakers() {
for speaker in speakers {
turnUpSpeaker(speaker)
}
}
func turnDownAllSpeakers() {
for speaker in speakers {
turnDownSpeaker(speaker)
}
}
func turnUpSpeaker(speaker:protocol<Powered,Audible>) {
if !speaker.on {
speaker.turnOn()
}
speaker.volumeUp()
println(speaker)
}
func turnDownSpeaker(speaker:protocol<Powered,Audible>) {
if !speaker.on {
speaker.turnOn()
}
speaker.volumeDown()
println(speaker)
}
turnUpAllSpeakers()

Before I explain anything else, I want to point out some really interesting information. There is a protocol called Printable, which allows you to output the textual representation of your type. To adopt Printable, you must add a description getter to your class. This does not make your class textual output go out to println(). There is also a protocol called DebugPrintable, which does the same sort of stuff as Printable but it is made strictly for debugging purposes. This protocol also does not print to the println() output. The only way (as far as I know) to override the output of the println() representation of the class is to inherit from NSObject and create a description method that returns a String. You output the description to that function, and println() prints your custom output. Remember, though, that there is no base class in Swift, as there is in JavaScript, Java, and tons of other programming languages. You are not inheriting a description from a grand base class; it just happens to be associated with that class. Also to use NSObject make sure you import UIKit or something similar.

The class Speaker adopts two protocols: Powered and Audible. The protocol composition happens in two places. You declare an array that takes only types that adopt those two protocols. You also created a turnUpSpeaker method, which takes the temporary protocol, which is made up of the two protocols. Luckily, the Speaker class fits the requirements just right, and you can pass in a Speaker. You provide Speaker with a way to turn on and off and a way to turn the volume up and down. You provide a max volume so you don’t exceed that volume, and you check to make sure the speaker is on before you turn it on. You create 10 speakers in a loop, using the range operator.

Why would you use protocol composition? Sometimes you have types that must match multiple protocols, and you can create a temporary protocol to meet the requirement.

Protocol Conformity

Sometimes it is necessary to check whether a type is of a protocols type. For example, if you create a Human class, which is Humanizable, you want to check an array of objects to see whether one of those elements conforms to the protocol. You use the is and as keywords to downcast the type to check its conformance to the protocol.

Using the keyword is returns true if the instance conforms to the protocol, and it is a good method to use if you do not need any downcast instance passed along to the inner scope of the if statement. If you do need a reference to the downcast instance, you can use the optional as? keyword. Here is an example of using both keywords. Notice that there is a little an extra detail you have to add in order to make this possible:

import Foundation

@objc protocol Animizable {
var name:String { get set }
}

@objc protocol Humanizable:Animizable {
var language:String { get set }
}

@objc protocol Bearable:Animizable {
func growl()
}

class Human:Humanizable {
var name:String = "Frank"
var language:String = "English"
}

class Bear:Bearable {
var name = "Black Bear"
func growl() {
println("Growllll!!!")
}
}

class Other:Animizable {
var name = "Other"
}

var lifeCollection:[AnyObject] = [Human(),Bear(),Other()]

for life in lifeCollection {
println(life)
if life is Humanizable {
println("is human")
}
if let humanizable = life as? Humanizable {
println(humanizable.language)
}
}

You have to add the @objc attribute in order to make this work. You use this attribute when you want your Swift code to be available to Objective-C code. However, you are not using it for that purpose here. If you want to check protocol conformance, then you must mark the protocol with that attribute even if you aren’t interacting with Objective-C code.

You can see that when you use the as? optional, you are able to call the language attribute of the Human, which would otherwise be just AnyObject. If you tried to get the language property of the Human from the isdowncast, you would get an error: error: 'AnyObject' does not have a member named 'language'. This is because you never actually downcast the AnyObject to a Humanizable. This is very powerful because you have protocols that inherit other protocols. You would get a wider range if you checked for the conformance of Animizable.


Note

The @objc attribute can be adopted only by classes, and not by structures or enums.


When you are looping through the array, you check for the conformance of the protocol with both is and as?. In the case of as?, if there is a match and the element does conform to the protocol, the optional is unwrapped and assigned to the let, using optional binding. At that point, the element of the array is no longer AnyObject but is known as type Humanizable. The object itself is not changed but merely temporarily downcast when it is stored in the constant.

Optional Protocol Prerequisites

If you peruse the Swift pseudo-code by Command+clicking protocols, you will see that a lot of them have optional requirements. For example, when you start a new project of any type, you can inspect UIApplicationDelegate, and you should see something like what Figure 8.1 shows.

Image

Figure 8.1 The UIApplicationDelegate protocol.

You can see that most of the methods of this protocol are optional and therefore do not need to be implemented. You can mark any method as optional so that the compiler will not throw an error if a method is not implemented. Even though you can’t see it in Figure 8.1, you need to mark a protocol with the @objc attribute if you plan on creating an optional method. This is true even if you are not planning on making your code available to Objective-C.

Let’s look at a quick example. Apparently, bears cough when they are scared. So in this example, you create an optional cough method of the Bearable protocol:

import Foundation

@objc protocol Animizable {
var name:String { get set }
}

@objc protocol Humanizable:Animizable {
var language:String { get set }
}

@objc protocol Bearable:Animizable {
func growl()
optional func cough() //Apparently bears cough when they are scared.
}

class Human:Humanizable {
var name:String = "Frank"
var language:String = "English"
}

class Bear:Bearable {
var name = "Black Bear"
func growl() {
println("Growllll!!!")
}
//Bear does not implement the cough method. He never gets scared.
}

Notice that you do not implement the cough method for the Bear class. You do not need to implement it because the protocol is marked optional for that method.

There is a possibility that you will try to call a method that does not exist at this point because it may not be implemented. In this case you would use optional chaining, discussed next.

Optional Chaining

When you have optional methods that may or may not exist, you need to be able to call them without the possibility of crashing your program. Did you think that the optional methods in protocols are just optional, meaning that you can include them or not include them? If you did, you were wrong. They are directly tied to optionals and can be checked via value binding.

Using optional chaining is another possibility instead of forcing the unwrapping of optionals. The big difference between optional chaining and forced unwrapping is that whereas forced unwrapping gives you an error and crashes your program if the thing you are looking for does not exist, optional chaining does not.

When you have an optional method that may or may not exist, you can use optional chaining to test for the existence of the method. To see how this works, you can expand your Bear example, like this:

class Bear {
var name = "Black Bear"
var paws:Paws?
func growl() {
println("Growllll!!!")
}
//Bear does not implement the cough method. He never gets scared.
}
class Paws {
var count = 4
}
var bear:Bear = Bear()
bear.paws = Paws()
println(bear.paws?.count) // Optional(4)

What is super interesting about this example is that the count of the paws returns an optional when it clearly was not set as an optional. That’s what optional chaining does for you: It allows you to safely write code with optionals in the middle. Let me explain a little further. The bear has optional paws. (Obviously, in a real-life bear, paws are never optional, but in this situation, they might be optional.) When you create a new Bear, you do not know whether the paws will exist or not. So you mark the paws as optional, like this:

bear.paws?

Now this is going to return either an instance of the paws as an optional or nil. The program cannot crash at this point because you will either get optional paws or nil. Optional chaining then marks everything within the optional paws as optional as well, even if it weren’t optional. So the count within the paws will become an optional Int. This is because the paws may not exist, so everything within the paws may not exist as well, and you don’t want the program to crash because of that. When you grab the count, like this, it is now an optional or nil, depending on whether the paws exist:

bear.paws?.count

This returns an optional, so now you can perform optional binding to get the unwrapped optional out:

if let count = bear.paws?.count {
println("The count was \(count)")
} else {
println("There were no paws")
}

Now you can test for the existence of the paws and get the count out of the optional that it was placed in.


Note

The biggest takeaway here is this: The paws may or may not have existed, and therefore everything within the paws had to be made an optional in order to not crash the program. That is the technique is called optional chaining. If one link of the chain is broken, then the whole thing crashes.


Back to Optional Protocol Requisites

With optional chaining tools in hand, you can now test to see whether your methods exist:

@objc protocol Bearable {
func growl()
optional func cough() -> String //Apparently bears cough when they are scared.
}

@objc class Bear:Bearable {
var name = "Black Bear"
func growl() {
println("Growllll!!!")
}
}

@objc class Forest {
var bear:Bearable?
func scareBears() {
if let cough = bear?.cough?() {
println(cough)
} else {
println("bear was scared")
}
}
}
var forest = Forest()
forest.scareBears()

You check whether the Bearable implementation exists with optional chaining. You assign the return of the method with optional binding, and if it is not nil, you print the output of the method; otherwise, you just print "the bear was scared".

Multiple chaining is going on in this situation. First, you check the optional bear, which could be nil. Then you check the optional cough method, which could also be nil and not implemented.

Useful Built-in Swift Protocols

Swift has a solid group of protocols you can implement in your classes to make stuff happen. The following sections describe them.

The Equatable Protocol

You use Equatable when you want one class to be comparable to another class, using the == operator. For example, if you have two Car classes that you want to compare for equality, you could adopt the Equatable protocol. You have to implement the == function (which can only be written on a global level), as shown here:

class Bear:Equatable {
var name = "Black Bear"
func growl() {
println("Growllll!!!")
}
}
func == (lhs:Bear, rhs:Bear) -> Bool {
return lhs.name == rhs.name
}
var bear1 = Bear()
bear1.name = "Black Bear"
var bear2 = Bear()
bear2.name = "Black Bear"
println(bear1 == bear2) //true

Here you are comparing two bears. You would not normally be able to do this because Swift would not know how to compare two bears. Thankfully, you can let Swift know how to compare them. In this case, you have Swift compare the bears by name. If the names are the same, then the bears are considered equal.

The Comparable Protocol

The Comparable protocol allows you to compare two objects by using at least the < operator. You can also override the other operators: >, >=, and <=. Consider that the less-than operator is required by law and Apple, and must be implemented on the global scope. Here’s how you can update the Bear class to make bears comparable by weight:

class Bear:Equatable,Comparable {
var name = "Black Bear"
var weight = 0
func growl() {
println("Growllll!!!")
}
}

func == (lhs:Bear, rhs:Bear) -> Bool {
return lhs.name == rhs.name
}

func < (lhs:Bear, rhs:Bear) -> Bool {
return lhs.weight < rhs.weight
}

var bear1 = Bear()
bear1.name = "Black Bear"
bear1.weight = 275
var bear2 = Bear()
bear2.name = "Black Bear"
bear2.weight = 220

println(bear1 == bear2)
println(bear1 < bear2) // false

Here you are implementing the Comparable protocol to give Swift a way to compare the bears by using at least the less-than operator. You then write the global less-than function and give it two parameters of type Bear. You can make as many of those global functions as you need, as long as the parameters that it accepts are different.

The Printable Protocol

The Printable protocol allows you to provide a textual representation of a class, a struct, or an enum. It is supposed to be able to be used by println, but that does not work as you would expect. It does make your life a whole lot simpler when creating text, though. Instead of having to write something like "my bear is \(bear1.name)", you can just write "my bear is \(bear1)". Printable works in an app but not in the playground or in the REPL (the command line Swift compiler, which can be run in Terminal using xcrun swift). You can add this protocol to be adopted by the Bear class like so:

class Bear:Equatable,Comparable,Printable {
var name = "Black Bear"
var weight = 0
var description:String {
return self.name
}
func growl() {
println("Growllll!!!")
}
}

func == (lhs:Bear, rhs:Bear) -> Bool {
return lhs.name == rhs.name
}

func < (lhs:Bear, rhs:Bear) -> Bool {
return lhs.weight < rhs.weight
}

var bear1 = Bear()
bear1.name = "Black Bear"
bear1.weight = 275
println("Our bear is \(bear1)")
var bear2 = Bear()
bear2.name = "Black Bear"
bear2.weight = 220
println("Our bear is \(bear2)")

println(bear1 == bear2)
println(bear1 < bear2)

Again, Printable does not work in playground or the Swift REPL. If you want to print to println in the playground or the REPL, a trick is to inherit from NSObject to create a function description that returns a String. You also have to delete Printable and its description from the computed property. Here’s what this trick looks like:

class Bear:NSObject, Equatable,Comparable {
var name = "Black Bear"
var weight = 0
func description() -> String {
return self.name
}
...

I am not sure if this is a bug in Swift or intended, but either way, this is a decent workaround.

The DebugPrintable Protocol

DebugPrintable is the same as Printable but used for debugging purposes. For its implementation, you use debugDescription instead of description. This protocol also does not work in the playground or the Swift REPL.

Summary

In this chapter you have learned how to create protocols of many different varieties. You’ve learned how to check for optional protocol methods and properties. There are many more protocols available to you in the Swift library. The ones described in this chapter are the most important ones to remember and will come in handy.

This chapter describes how to create a protocol and all the different ins and outs of protocols, but in the end, it is up to you to know the right time for a protocol. After practicing with them for a while, I began to find myself using them more often and in really neat ways. For example, I created a text-based game in which anything that was able to be picked up fell into a protocol I created called PickableUpable. I then passed around PickableUpables instead of looping through each different thing that could be picked up. Then, using optional downcasting, I checked whether each item was the PickableUpable that I wanted. Sure, I could have called it PickUpable, but what fun would that be?

When you combine protocols with generics, you’ll have a lot of power. You already have some great tools for abstracting code and making it reusable. With generics you will be able to apply your protocols to generics to make methods work with any type of object that meets certain criteria.