Swift protocols

What is a Protocol? It is a list of requirements which have to be implemented by conforming types, similar to a contract. The compiler will give an error if the type adopting the protocol does not conform (aka does not implement the protocol requirements).

This list of requirements defines the minimum set of properties and methods which a confirming type must implement. That type can, of course, go beyond the protocol’s requirements.

How to define a protocol? It is very similar to defining a structure or class; the only change is that you do not write the implementation code.

Defining properties and methods

Properties

A protocol can require that conforming types provide specific properties. This applies to type properties as well (using the keyword static)

You define it like any other variable, but without the assignment of value. Furthermore, the protocol only states if the property is read-only or read write, by using either {get} for read-only or {get set} for read-write

Methods

A protocol can also require that conforming types provide specific methods. This applies to type methods as well.

It also applies to mutating methods: if we intend that a method of a type conforming to a protocol can modify the instance of that type, we must declare it as such in the protocol. Mutating methods only work on value types (e.g. structure)

How do you use the protocol?

In my example, you ask a type to conform to the MyProtocol by using the same notation as with class inheritance. You have to at minimium give implement the properties and methods of the protocol MyProtocol (name, id, typeProperty and printDetails()).You are free to implement more properties in the struct if you so wish. Conforming to the protocol is the minimum requirement that needs to be met when defining a type:

Optional requirements

Protocols marked to have an optional implementation of properties or methods can only be used with classes. Using them on a struct or enum will give you a compiler error: non-class type ‘UserDetailsStruct’ cannot conform to class protocol ‘ContactDetails’

To mark a protocol as an optional you have to use the keyword @objc for the protocol and @objc optional in front of the properties and methods. This way, the conforming type has the option to omit the implementation of this properties and methods.

As you can see below, the property emailAddress was not implemented, and the compiler didn’t scream at us:)

Protocol inheritance

As the name of the concept says, it is about a protocol inheriting … from other protocols (even more than 1). In practice, this means that a conforming type will have to conform to all the protocols inherited by the protocol it is conforming to. A bit confusing but see below for an example.

Below, the type randomDriver is conforming to protocol Circuit, which means that it has to implement the properties (and methods) found in the two other protocols (ProDriver and Driver).

Protocol composition

This seems to increase my flexibility, when compared to OOP, where a subclass can only inherit from a single superclass. This represents the possibility of a type conforming to multiple protocols.

Why use it? it allows us to develop a kind of plug-in system where we pick and choose the requirements that we need for our type and only implement those that are therefore relevant.

The implementation is listed below where we have a series of protocols and two different types which use those protocols to implement their specific requirements: ProDriver is different than Amateur Driver, and they, therefore conform to different protocols.

Protocols are also types

What does that mean? we can use them as function parameters or return types, or as types for variables, constants or collections (e.g. array, dictionaries)

What we can’t do with protocols, is use them to create an instance of that protocol, because a protocol has no implementation.

Why is this useful? For example, we can assign a class or struct conforming to a specific protocol, to a collection type conforming to that protocol. This is a form of polymorphism.

Polymorphism

We can interact with multiple types through a single interface. For example, if you set a variable to be of type Int, it only accept Ints, however, if you set it to be a protocol type, it will accept instances of any type conforming to the protocol.

Below we use the protocol PersonProtocol as the type for the person parameter in the updatePerson() function, as well as the return type of the same function. This means that the parameter person takes a value that conforms to the PersonProtocol, which in this case is firstPerson (as defined above the var changedPerson). The aim of the function is to change the profession value of the type conforming to the PersonProtocol protocol.

Another example of polymorphism uses a collection type. Below, the personArray array accepts any type that conforms to the PersonProtocol protocol, which in this example is a struct and a class. Normally, you can only have the same types in in array.

And below for dictionaries:

This also works with properties:

Associated types with protocols

What are these? A type alias it is used as a placeholder name in the protocol in place of a type. In the places you are using a type in a protocol, for example when you are declaring a property or the parameter type/return type of a method, you can replace that type with this associated type. This means that you can assign different types when implementing the requirement of the protocol.

The type of the associated type to use is not defined until the protocol is being implemented.

As you can see below, I defined typeName as my associatedType and used it as the parameter type in the add method, as well as the optional return type for the get method.

Further down, in the struct myStuff, I replaced the typeName with String and therefore assigning the string type as the protocol type. Associated types let you define the type of the protocol properties and methods at the moment of implementation.

There is still more to cover on protocols:

  • Protocol type casting
  • Protocols extensions
  • Protocol constrains
  • Delegation
Show your support

Clapping shows how much you appreciated Cosmin Mircea’s story.