All about protocols in swift

Protocol oriented programming , like functional programming is an important concept in swift . I am learning protocols in swift and I am documenting it here. Everything I know about protocols will be here in this article. Do read and update your knowledge.

Abhimuralidharan
11 min readJul 29, 2017

Source : Apple Docs

A protocol defines a blueprint of methods, properties, and other requirements that suit a particular task or piece of functionality. The protocol can then be adopted by a class, structure, or enumeration to provide an actual implementation of those requirements. Any type that satisfies the requirements of a protocol is said to conform to that protocol.

So, keeping it simple, a protocol says a struct , class or enum that if you want to be THAT, do THIS, this and THis. Example: if you want to be a human, you have to EAT, SLEEP, and Take REST and repeat!!! 🤓.

Protocol Syntax

protocol syntax

Classes , structs, enums can adopt these protocol by placing protocol’s name after the type’s name, separated by a colon, as part of their definition. Multiple protocols can be listed, and are separated by commas:

struct adopting multiple protocols

If a class has a superclass, list the superclass name before any protocols it adopts, followed by a comma:

Classes with superclass

Both swift and Objective — C supports multi level inheritance. It can only have one single base class. Multiple inheritance is not supported by both. Only multiple inheritance of protocols are supported separated by commas as shown in the previous image.

You might have already seen UIViewControllers implementing UITableview datasource and delegate protocols.

class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate { }

Although, the best practice is to group this in a separate extension of ViewController and implement the protocols.

class ViewController: UIViewController {}extension ViewController: UITableViewDataSource, UITableViewDelegate
{
//implement protocol methods ands variables here..
}

Adding Property Requirements

  • A protocol can have properties as well as methods that a class, enum or struct conforming to this protocol can implement.
  • A protocol declaration only specifies the required property name and type. It doesn’t say anything about whether the property should be a stored one or a computed one.
  • A protocol also specifies whether each property must be gettable or gettable and settable.
  • Property requirements are always declared as variable properties, prefixed with the var keyword.
  • Gettable and settable properties are indicated by writing { get set } after their type declaration, and gettable properties are indicated by writing { get }.
get-set and get

Note:

  • A { get set } property cannot be a constant stored property. It should be a computed property and both get and set should be implemented.
  • A { get } property can be any kind of property, and it is valid for the property to be also settable if required.

Stored and computed properties are usually associated with instances of a particular type. However, properties can also be associated with the type itself. Such properties are known as type properties.

  • Always prefix type property requirements with the static keyword when you define them in a protocol. This rule pertains even though type property requirements can be prefixed with the class or static keyword when implemented by a class:
type properties in a protocol declaration

What does conforming to a protocol means?

As explained earlier, a protocol says that you need to do few things in order to become something.

Example: if you want to become a bird, you should fly . Or you should conform to Flyable protocol.

Consider the following example:

simple protocol conformation

Here, we declared a protocol named FullyNamed . It has a gettable stored property called fullName of type string .

Now, we are defining a struct called Person and we are saying that the struct conforms to the FullyNamed protocol. This means that we should implement the fullName string variable inside the struct defined. Otherwise it will throw an error on us.

We can also define the fullName property as a computed property.

protocol conformation as computed property

Method Requirements

As mentioned earlier, protocols can have methods as well.

  • A protocol can have type methods or instance methods.
  • Methods are declared in exactly the same way as for normal instance and type methods, but without curly braces or a method body.
  • Variadic parameters are allowed.
  • Default values are not allowed.
  • As with type property requirements, you always prefix type method requirements with the static keyword when they are defined in a protocol. This is true even though type method requirements are prefixed with the class or static keyword when implemented by a class:

Consider the following example. These are self explanatory I believe:

Struct conforming to a protocol having methods
class conforming to a protocol having methods

Note: In the above class implementation. someStaticMethod(variadicParam:) method is defined as a class method. In the protocol declaration, it is defined as static method.

Protocols with mutating methods

source: Article

Mutating methods are methods that we use on value types like structs and enums. These methods are allowed to modify the instance it belongs to and any properties of that instance. A small example:

Consider a simple struct Rectangle:

Struct with mutation functions

The scaleBy(value:) method modifies the value of width and height. So it should be marked as mutating. Otherwise the compiler will throw error at you.

Coming back to mutating method requirements:

If you define a protocol instance method requirement that is intended to mutate instances of any type that adopts the protocol, mark the method with the mutating keyword as part of the protocol’s definition.

If you mark a protocol instance method requirement as mutating, you do not need to write the mutatingkeyword when writing an implementation of that method for a class. The mutating keyword is only used by structures and enumerations.

Consider an enum and class implementing a protocol with mutating function:

enum and class implementing a protocol with mutating function

The lightSwitch object should be var as OnOffSwitch is a value type.

Initializer Requirements

Protocols can have specific initializers like normal methods which the conforming types can implement.

protocol with initializers

Class Implementations of Protocol Initializer Requirements

You can implement a protocol initializer requirement on a conforming class as either a designated initializer or a convenience initializer. In both cases, you must mark the initializer implementation with the requiredmodifier:

class conforming to protocol initializers

If a subclass overrides a designated initializer from a superclass, and also implements a matching initializer requirement from a protocol, mark the initializer implementation with both the required and overridemodifiers:

protocol SomeProtocol {init()}class SomeSuperClass {init() {// initializer implementation goes here}}class SomeSubClass: SomeSuperClass, SomeProtocol {// "required" from SomeProtocol conformance; "override" from SomeSuperClassrequired override init() {// initializer implementation goes here}}

Failable Initializer Requirements

Protocols can have failable initializers. A failable initializer requirement can be satisfied by a failable or nonfailable initializer on a conforming type. A nonfailable initializer requirement can be satisfied by a nonfailable initializer or an implicitly unwrapped failable initializer.

Protocols as Types

Protocol is a type. You can use it in many places like:

  • As a parameter type or return type in a function, method, or initializer
  • As the type of a constant, variable, or property
  • As the type of items in an array, dictionary, or other container
  • Because protocols are types, begin their names with a capital letter to match the names of other types in Swift (such as Int, String, and Double).

Delegation

Delegation is a design pattern that enables a class or structure to hand off (or delegate) some of its responsibilities to an instance of another type. Delegation pattern can also be used as a callback kind of mechanism.

The following code is self explanatory for a swift developer with intermediate level of knowledge. If you have any doubt , please comment below.

delegation callback

Adding Protocol Conformance with an Extension

You can extend an existing type to adopt and conform to a new protocol, even if you do not have access to the source code for the existing type. Extensions can add new properties, methods, and subscripts to an existing type, and are therefore able to add any requirements that a protocol may demand.

Adding Protocol Conformance with an Extension

Declaring Protocol Adoption with an Extension

If a type already conforms to all of the requirements of a protocol, but has not yet stated that it adopts that protocol, you can make it adopt the protocol with an empty extension:

Types do not automatically adopt a protocol just by satisfying its requirements. They must always explicitly declare their adoption of the protocol.

Declaring Protocol Adoption with an Extension

Consider the class Animal. It has an optional Int? computed property called age . This makes the class conforming to the protocol Growable . So in order to use the class anywhere where the required type should conform to the protocol, use a simple empty extension of Animal class conforming to the Growable protocol.

Collections of Protocol Types

Protocols can be used as a type to be stored in collection types like array or dictionary.

Collections of Protocol Types

Since, Animal and Human conforms to the Growable protocol, they can be stored in an array of type Growable .

Protocol Inheritance

A protocol can inherit one or more other protocols. The syntax of protocol inheritance is similar to class inheritance.

protocol inheritance

Suppose there is a struct conforming to the Inheriting protocol, it should also conform and satisfy all the other protocols that Inheriting protocol inherits from.

Class-Only Protocols

You can limit protocol adoption to class types (and not structures or enumerations) by adding the AnyObject or class protocol to a protocol’s inheritance list.

Class-Only Protocols

In the example above, SomeClassOnlyProtocol can only be adopted by class types. It is a compile-time error to write a structure or enumeration definition that tries to adopt SomeClassOnlyProtocol.

If a non — class type tries to conform to this protocol, the compiler will show error like:

error: non-class type ‘XXXXXXXX’ cannot conform to class protocol “YYYYYY.”

Protocol Composition

Sometimes it is required for a type to conform to multiple protocols. Image a function which accepts a parameter which should conform to multiple protocols.

You can combine multiple protocols into a single requirement with a protocol composition. Protocol compositions behave like you defined a temporary local protocol that has the combined requirements of all protocols in the composition. Protocol compositions don’t define any new protocol types.

In swift 3 & 4, protocol compositions have the form SomeProtocol & AnotherProtocol. You can list as many protocols as you need to, separating them by ampersands (&). In addition to its list of protocols, in swift 4, a protocol composition can also contain one class type, which lets you specify a required superclass. This is not possible in swift 3.

Protocol Composition swift 4

Note: Swift 3 syntax for protocol composition is same. But it doesn’t allow us to add Class name along with the protocols using & sign. The playground is throwing error when I tried to add the Animal class in the composition list.

Checking for Protocol Conformance

You can use the is and as operators described in Type Casting to check for protocol conformance, and to cast to a specific protocol. Checking for and casting to a protocol follows exactly the same syntax as checking for and casting to a type:

  • The is operator returns true if an instance conforms to a protocol and returns false if it does not.
  • The as? version of the downcast operator returns an optional value of the protocol’s type, and this value is nil if the instance does not conform to that protocol.
  • The as! version of the downcast operator forces the downcast to the protocol type and triggers a runtime error if the downcast does not succeed.

Optional Protocol Requirements

Protocol can have optional methods and properties.These requirements do not have to be implemented by types that conform to the protocol.

Optional requirements are prefixed by the optional modifier as part of the protocol’s definition. Optional requirements are available so that you can write code that interoperates with Objective-C. Both the protocol and the optional requirement must be marked with the @objc attribute. Note that @objc protocols can be adopted only by classes that inherit from Objective-C classes or other @objcclasses. They can’t be adopted by structures or enumerations.

First, we add @objc keyword in front of the protocol keyword. Then we add the @objc optional keyword in front of our optional method/variable.

When you use a method or property in an optional requirement, its type automatically becomes an optional.

optional Protocol Requirements

Protocol Extensions

Protocols can be extended to provide method and property implementations to conforming types. This allows you to define behavior on protocols themselves, rather than in each type’s individual conformance or in a global function.

Protocol extensions

Providing Default Implementations using protocol Extensions

Protocol extension can be used for providing default implementation within the protocol itself as explained in the previous section.

Important: If a conforming type provides its own implementation of a required method or property, that implementation will be used instead of the one provided by the extension.

Providing Default Implementations using protocol Extensions

This is the same example used to explain the protocol extensions. But here the Fan class defines rotates property by its own. So , the definition inside the protocol extension will be ignored. The default implementation returns false while the definition inside the Fan class returns true. Just have a look at the output on the right .

Adding Constraints to Protocol Extensions

When you define a protocol extension, you can specify constraints that conforming types must satisfy before the methods and properties of the extension are available. You write these constraints after the name of the protocol you’re extending using a generic where clause.

Adding Constraints to Protocol Extensions

In the above example, it says that the Array collection can implement the Equatableprotocol only when its elements are themselves Equatable .

That’s it . Now you know what a protocol is and where to use them.

Enjoy!!

If you enjoyed reading this post, please share and recommend it so others can find it 💚💚💚💚💚💚 !!!!

You can follow me on Medium for fresh articles. Connect with me on LinkedIn.

If you have any comment, question, or recommendation, feel free to post them in the comment section below!

--

--