A protocol defines a “blueprint of methods, properties, and other requirements that suit a particular task or piece of functionality”. They can give also give nominal types polymorphic behavior.

In Swift, the “protocol can then be adopted by a class, structure [a struct], or enumeration [an enum] to provide an actual implementation of those requirements. Any type that satisfies the requirements of a protocol is said to conform to that protocol” (Ref#: G).

Expanding on this further, a protocol is essentially a list of method declarations and property requirements. If you want a class to adopt a protocol, you implement those methods in your class, or you give your class any properties that are required.

Swift Protocol Syntax

The syntax for creating protocols in Swift is really straight forward:

If we’re using this protocol with a structure, a struct it’s going to look like this:

And similarly, when we want to use a protocol in a class it looks like:

Objective-C Protocol Syntax

A protocol in Objective-C will look like this:

To adopt a protocol, add it to your class header file like:

The protocol names appear after the class declaration, inside angled brackets. When adopting more than one protocol, list them in a comma-separated list.

Then in your implementation (.m) file, implement all of the required methods for each protocol. (For Cocoa classes, consult the documentation to see which methods are required and which are optional.)

Optional Protocol Methods

So from the stage of Objective-C 2.0 and later, and indeed in Swift, some protocol methods can be marked as optional. This means you don’t have to implement those, but you still have to implement all of the required methods. As we mentioned above, when you do this your class is said to conform to the protocol.

Note that when using in Swift, when we want an optional method, we do need to tap into some Objective-C by using the @objc attribute as a prefix of the optional method in the Swift protocol:

However, we then have the advantage of being able to check for a function’s existence when using it by taking advantage of optional-chaining, like this:

Meaning that the method will only be tried if it is available in the class that is conforming to the protocol.

Class Only Protocols (Swift)

AnyObject refers to any instance of a class and is equivalent to id in Objective-C. It’s useful when you specifically want to work with a reference type because it won’t allow any of Swift’s structs or enums to be used. AnyObject is also used when you want to restrict a protocol so that it can be used only with classes. As of Swift 4. protocol P : class {} and protocol P : AnyObject {} parse identically and there’s no semantic difference between them, whereas previously there had been some subtle differences, this means that the AnyObject syntax is now preferred

Protocols in the Cocoa Framework

Protocols are used a lot in iPhone development and in the Cocoa framework. A really good example is that a UITableView requires a data source and a delegate object, and these must conform to the UITableViewDataSource and UITableViewDelegate protocols.

Property Requirements (Swift)

In Swift – property requirements look like:

Note that we must specify whether the property should be read-only or read-write in nature and the way we do this is using the get and set keywords.

Method Requirements (Swift)

Initializer Requirements (Swift)

“Protocol can require specific initializers to be implemented by conforming types”(Ref: #F).

See more information on designated vs convenience initializers in Swift see my article here: https://www.steveclarkapps.com/initializers/

Swift Protocols Are Different

Swift protocols are a lot different from good old Objective-C protocols – Swift Protocols support:

  • Protocol Inheritance
  • Protocol Extensions
  • Default Implementation
  • Associated Types (Generics)
  • Conformed to by Structs and Enums (value types) as well as Classes (reference types).

In WWDC 2015 Swift was described as being a “Protocol Oriented Language”.

Protocol Inheritance (Swift)

“A protocol can inherit one or more other protocols and can add further requirements on top of the requirements it inherits. The syntax for protocol inheritance is similar to the syntax for class inheritance, but with the option to list multiple inherited protocols, separated by commas” (Ref#: F).

Protocol Extensions (Swift)

“Protocols can be extended to provide method, initializer, subscript, and computed 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” (Ref#: F).

“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 by writing a generic where clause.”(Ref#: F).

Default Implementation (Swift)

“You can use protocol extensions to provide a default implementation to any method or computed property requirement of that protocol. 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”(Ref#: F).

For example:

Associated Types (Swift)

An associatedtypeis a placeholder for an unknown Concrete Type in a swift protocol which will require concretization on adoption at Compile time, and as such is seen as an example of Generics. In the words of Paul Hudson, “they mark holes in protocols that must be filled by whatever types conform to those protocols”.

Here’s an example:

“Associated types are effectively holes in a protocol, so when you make a type conform to this protocol it must specify what ItemType actually means”.

( https://www.hackingwithswift.com/articles/74/understanding-protocol-associated-types-and-their-constraints )

Benefits of Using Associated Types

“This concept first appeared in a publication from “The Journal of Functional Programming” titled: extended comparative study of language support for generic programming. Where they laid emphasis on Multi-Type Concepts which is the root of Swift’s protocol associatedtypes. Swift also drew some inspiration from Scala’s Traits and Abstract types, Haskell’s Multi-parameter type classes and from Rust Associated Types. It then leveraged the Multi-Type Concept within the standard library for [its] collection types”(Ref#: W).

Associated Types help specify the precise and exact Type of an object within a protocol sub-typing without polluting the Type definition.

“associated types allow the adopter of a protocol to provide multiple concrete types at compile-time, without polluting the type definition with a bunch of type parameters. They’re an interesting solution to the problem and a different kind of abstraction (abstract members) from generic type parameters (parameterization)”(Ref#: X).

N.B. associated types do differ from generic type parameters, although both have similar aims.

Protocol Oriented Programming (POP) in Swift

Many of us have heard the term Protocol Oriented Programming banded about in the land of Swift programming. However, everywhere we look when researching the topic, we struggle to come up with a single phrase that actually defines what POP is (which can lead to some confusion).

Let’s try our best here to come up with such a phrase. By “protocol” those who talk about POP are meaning very specifically Swift protocols (which are perhaps more similar to C++ abstract classes then Objective-C protocols); these are protocols which can be conformed to by value types like Structs and Enums which are “first-class citizens” in Swift, as well as reference types like normal classes. It turns out that POP is mostly OOP but with a different emphasis; the emphasis on composition over inheritance.

So a phrase that I have come up with to explain what I believe Apple means by POP is “A version of OOP which emphasizes composition over inheritance as a method of functionality-sharing (by using Swift’s version of Protocols)“.

In Swift, our value types like Structs and Enums can have properties, methods, and extensions. POP is a pattern that encourages us to use flat, non-nested structures in our code, whereas inheritance is conversely not a flat way of structuring things.

Use of Value vs Reference Types

Swift classes have reference semantics (passed by reference), but Swift also supports enums and structs that are passed by value, and these enums and structs are also able to support many of the features provided by classes. By using POP, we are steering away from class inheritance and instead favoring the use of value types because:

  • When we subclass from some superclass we have to inherit all its properties and methods, some of which we may not need or want. This can mean our object getting bloated with a lot of unnecessary code.
  • With a deeply nested structure of inheritance, it can be really hard to know where a problem is coming from as we need to jump up and down the hierarchy in order to find and fix bugs.
  • Because inheritance uses classes which are reference types we can get unforeseen consequences from modifying a property in an instance of a class, such that we may end up with spaghetti code scenarios.
  • A goal of ours should be to separate the public interface from the private implementation where we can (see SOLID principles).
  • We want our software to be defined in components that talk to each other using interfaces.
  • We want reusability, extensibility, black-boxed functionality, in order to make our code a hell of a lot more maintainable going forward.
  • We want to make our code more testable with unit tests, and we want to be able to inject our dependencies using dependency injection, which is all facilitated by a more modular approach.

(Sources Ref#: Q, Ref#: U).

Why would we go for a protocol-oriented approach in our code? …and is there a way we can use protocols (and value types) to make our code better?

Composition over Inheritance (also known as the composite reuse principle) is an OOP principle about achieving polymorphic behavior and code re-use via composition (typically through containing instances of other classes that implement the desired functionality – but in POP via protocol adoption) rather than inheritance from a base class (as elucidated in the famous GoF Design Patterns book).

The benefits of Composition over Inheritance include: “It is more natural to build business-domain classes out of various components than trying to find commonality between them and creating a family tree”.

Composition is also less prone to the quirks of the family members because it’s better to compose what an object can do than extend what it is. The reason this is better is that it more easily accommodates future requirements changes that would otherwise require a complete restructuring of business-domain classes in the inheritance model. It means that making small changes in a part of an inheritance model need not potentially cause a raft of unforeseen consequences down the chain of inheritance (Ref#: P).

What Composition Can Look Like

Obviously, what we are doing with composition is allowing our object to conform to one or more protocols. For example, a tableview cell might be designated as Completable where Completable is a protocol that requires a variable complete that tells us if a form cell is complete. But this cell could also be made to conform to any number of other protocols, building up an idea of how we can reasonably treat the cell given that we know that it conforms to a given set of protocols.

This will let out types adopt multiple protocols which can prove a big advantage as is get rid of the need to use a class hierarchy. We can take our requirements and break them down into smaller components, avoiding bloated types that may contain requirements that are not really needed by all the types that inherit from them.

Using frameworks like GRDB gives us examples like (allowing us to use the same struct to both parse API data, as well as save data to a local SQLite database):

Another Example

Source: https://www.pluralsight.com/guides/protocol-oriented-programming-in-swift

Default Behaviors using Protocol Extensions

Protocols can have extensions: in Swift, you can actually add default functions and properties on protocols by Extending protocols with default behaviors.

(Source: U)

(Source: V)

What is “Local Reasoning”?

In the last few years at Apple’s WWDC conference (known in the community as dub dub) there have been several talks about moving towards a Protocol Oriented approach to programming (particularly in Swift). In one such talk the concept of “Local Reasoning” was covered.

Local Reasoning means that a programmer reading a piece of code can make sense of that code without having to go on a journey around the wider codebase to find out what’s actually going on. It more broadly means that you can reason about a software unit (like a module, or function) as a separate thing.

So one benefit of this POP approach that Apple is now advocating is said to be that this local reasoning is easier to do, potentially making it faster to improve or modify features of our app in our Swift code.

Protocols as Types

Although protocols don’t contain business logic, they are still considered fully-fledged types in Swift and therefore they can be used (to a large extent) like any other type. This means that we may use protocols both as parameters and return types for our functions. They may also be used to define the type of vars, constants, and objects like arrays (Ref#: T).

Use of Protocols in the Delegate Pattern

In Swift, when we want to use a delegate pattern, we typically do this by creating a protocol that defines the responsibilities of a delegate. In this context, any type that conforms to this protocol is called the delegate and it will adopt this protocol ensuring that it will provide the required functionality that has been specified in the protocol. We obviously see this pattern used very extensively in Cocoa, and most typically in things like the UITableViewDelegate and UITableViewDatasource. But, more powerfully, we can create our own protocols such as when we want some cell to return some detailed information back to the context from which it was generated in some specific format.

Conclusion

In this article, we have covered the fact that a protocol (in iOS programming) is a blueprint of methods, properties, and other requirements that suit a particular task or piece of functionality”.

We have covered how we define a protocol in Objective-C and Swift, and how Swift protocols can end up being used with both classes and struct, if not restricted by the use of the class or AnyObject conformance such that they may then only be conformed to be classes.

We discovered that Protocol-Oriented Programming is an Apple buzz term, which, as I have defined it, means something like “A version of OOP which emphasizes composition over inheritance as a method of functionality-sharing by using Swift’s version of Protocols”. We also found out that protocols can help with what Apple calls “local reasoning” or the ability to see what a piece of code is doing just from looking at that scope in code, and without having to search to the codebase to establish this.

We found that Swift Protocols and POP aim to provide us with all the benefits of composition over inheritance for a flatter, more transparent and readable code structure, as opposed to a system based on inheritance where we might have a lot of inherited stuff in our classes that we don’t actually need or use.

References

A: https://www.youtube.com/watch?v=ekYdBcl3dzs&feature=push-u&attr_tag=WCN9zigcfLq3t6Rk-6

B: For Obj-C: http://www.idev101.com/code/Objective-C/protocols.html

C: For Swift: https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Protocols.html#//apple_ref/doc/uid/TP40014097-CH25-ID267

D: https://www.youtube.com/watch?v=2CMsgER7WG4 (Retroactive Modeling with POP)

E: https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/ProgrammingWithObjectiveC/WorkingwithProtocols/WorkingwithProtocols.html

F: https://docs.swift.org/swift-book/LanguageGuide/Protocols.html

G: https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Protocols.html

H: “https://medium.com/@abhimuralidharan/all-about-protocols-in-swift-11a72d6ea354”

I: https://www.raywenderlich.com/148448/introducing-protocol-oriented-programming

J: https://developer.apple.com/videos/play/wwdc2015/408/

K: https://developer.apple.com/videos/play/wwdc2016/419

L: “https://www.youtube.com/watch?v=ekYdBcl3dzs”

M: https://www.youtube.com/watch?v=g2LwFZatfTI

N: https://www.raywenderlich.com/814-introducing-protocol-oriented-programming-in-swift-3

O: https://www.appcoda.com/protocol-oriented-programming/

P: https://en.wikipedia.org/wiki/Composition_over_inheritance

Q: https://blog.bobthedeveloper.io/introduction-to-protocol-oriented-programming-in-swift-b358fe4974f

R: https://www.slideshare.net/yltastep/protocoloriented-programming-in-swift

S: https://medium.com/@agoiabeladeyemi/protocol-in-swift-with-practical-examples-8b955268ce39

T: Hoffman, J. (2019). Swift Protocol-Oriented Programming – Fourth Edition. Pakt Publishing, Birmingham, UK.

U: https://www.tensorflow.org/swift/tutorials/protocol_oriented_generics

V: https://team.goodeggs.com/overriding-swift-protocol-extension-default-implementations-d005a4428bda

W: https://medium.com/@bobgodwinx/swift-associated-type-design-patterns-6c56c5b0a73a

X: http://www.russbishop.net/swift-associated-types

 

Last Updated: 31/05/2019

Loading

Last modified: January 20, 2020

Author

Comments

Write a Reply or Comment

Your email address will not be published.