A protocol defines a blueprint or a set of requirements that are needed to accomplish a particular task. Classes, structs, and enums can conform to protocols by providing an implementation of the protocol’s functions and properties.
The definitions of protocols are very similar to classes and structs. However, in the case of protocols, the definition does not implement the properties and functions. Instead, the class or struct that adopts the protocol handles the implementation of the properties and methods. Any type that satisfies the requirements of the protocol as described above is said to conform to the protocol.
protocol WelcomeMessagePrinting { func printHello(message: String) }
In the example above, we have a protocol named WelcomeMessagePrinting
. Inside the protocol, there is a function called printHello()
. This function would be implemented by the class or struct that adopts WelcomeMessagePrinting
.
struct MyStruct: WelcomeMessagePrinting { func printHello(message: String) { print(message) } }
As mentioned earlier, properties can also be a part of protocols.
protocol WelcomeMessagePrinting { var helloMessage: String { get } func printHello() }
Notice that in the above example we have introduced a String
type property named helloMessage
. There are a couple of things to know here:
- The protocol definition must specify if the conforming class/struct/enum needs to implement just the getter for the property or both the getter and setter methods.
- If the property is defined as
get
, then the conforming type can choose to either provide the getter method, which is the minimum requirement or provide both the getter and setter methods.
Let’s now create a struct that conforms to WelcomeMessagePrinting
:
struct Hello: WelcomeMessagePrinting { var helloMessage: String { return "Welcome" } func printHello() { print(helloMessage) } }
Note that to add protocol conformance, the struct Hello
needs to be followed by a :
and the protocol name.
Sometimes protocols have multiple functions and the implementation can be long, so it is common to move the protocol implementation to a separate extension as follows:
extension Hello: HelloPrinting { var helloMessage: String { return "Welcome" } func printHello() { print(helloMessage) } }
The printHello()
function can then be called as follows:
let hello = Hello() hello.printHello() // Prints: Welcome
Multiple types can conform to the same protocol. For instance, in the following example we have NewUserWelcomeView
struct conforming to WelcomeMessagePrinting
:
struct NewUserWelcomeView: WelcomeMessagePrinting { var helloMessage: String = "Thanks for signing up!" func printHello() { print(helloMessage) } }
And then the ReturningUserWelcomeView
also conforms to WelcomeMessagePrinting
:
struct ReturningUserWelcomeView: WelcomeMessagePrinting { var helloMessage: String = "Welcome back!" func printHello() { print(helloMessage) } }
Note that the helloMessage
for the structs above are different - that’s the flexibility that protocols allow us.
We can invoke the printHello()
function on instances of the structs as given below:
var view: WelcomeMessagePrinting view = NewUserWelcomeView() view.printHello() // Prints: Thanks for signing up! view = ReturningUserWelcomeView() view.printHello() // Prints: Welcome back!
Note that view
is declared as WelcomeMessagePrinting
type, which means that it can be of any type that conforms to the WelcomeMessagePrinting
protocol.
Instructions
Create a protocol named Incrementable
that has a property called currentValue
of type Double
and a get
method. It should also have a mutating function called increment()
that takes no arguments and does not return anything.
Create a struct named VisitorCounter
that conforms to Incrementable
. Add a currentValue
property and assign it 0.0. Add an increment()
method that increases the value of currentValue
by 1.
Create another struct named Wage
that conforms to Incrementable
. Set currentValue
to 15.0 in this case. In the implementation of increment()
, increase the value of currentValue
by 10%.
Create a variable called parkGuests
of type VisitorCounter
. Call increment
on parkGuests
and print the currentValue
of parkGuests
.
Create a variable called salary
of type Wage
. Call increment()
on salary
. Then print the currentValue
of salary
.