Swift — The Protocol Way (Chapter 1)

Ankur JAIN
4 min readMar 5, 2019

--

Gentle Protocols

Motive

The motive of this post to go through one of the best coding objects, Protocols. We can enhance our coding practices and architecture using Protocols. Protocols not only works as an interface for many classes but also provides you a strong architecture, which is reusable and less error-prone. We all are fond of classes, now lets dive into the universe of Protocols. Let’s begin.

Protocols

Protocols are a way to specify how to use objects. They specify properties, methods which can be implemented by classes, structs, and you know one thing, they can also be implemented by enums in swift. This is a very powerful feature when comes to create utility objects which have functionalities that can be reused in multiple objects. Do not want to confuse you more, let’s try some practical

protocol MyProtocol {    init(value: Int) // required initializer    func doSomething() -> Bool // instance method    var message: String { get } // instance read-only property    var value: Int { get set } // read-write instance property    subscript(index: Int) -> Int { get } // instance subscript    static func instructions() -> String // static method    static var max: Int { get } // static read-only property    static var total: Int { get set } // read-write static property
}

This is a sample blueprint of a Protocol with all the capabilities. It has initializers, properties, methods, static properties.

protocol Walkable{
func walk()
}
protocol Swimmable{
func swim()
}
protocol Breathable{
func breathe()
}
protocol Flyable{
func fly()
}

These are the protocols which possess some of the capabilities of living beings on this planet. These can be implemented by different types of living beings based on the capability that living being has. Let’s see this in example

class Human: Walkable, Swimmable, Breathable{
func walk() {
print("Human is walking...!")
}
func swim() {
print("Human is swimming...!")
}
func breathe() {
print("Human is breathing...!")
}
}
class Animal: Breathable,Walkable{
func breathe() {
print("Animal is breathing...!")
}
func walk() {
print("Animal is walking...!")
}
}
class Man: Human{
override func breathe() {
print("Man is breathing...!")
}
}
class Woman: Human{
override func walk() {
print("Woman is walking...!")
}
}
class Bird: Animal,Flyable{
func fly() {
print("Bird is flying...!")
}
}
class Dog: Animal{
func bark(){
print("Dog is barking...!")
}
override func walk(){
print("Dog is walking...!")
}
}
class Fish: Animal,Swimmable{
func swim() {
print("Fish is swimming...!")
}
}

As you can see, classes like Human and animal conform to the protocols according to their capabilities. These methods can also be overridden by the subclasses to give its own logic to handle, like what we are doing in Man and Woman class.

If you don’t implement the required methods of the protocols, it’s gives compiler error thus making it less error-prone.

Abstract Type To Conform to Multiple Protocols

You can also conform to multiple protocols based on the situations. In swift, you do it by joining the protocols with the & operator.

Example Below:

var abstract: Flyable & Swimmable//Methods to Expect abstract Type:func abstractMethod(object: Flyable & Walkable){}//Calling this method
abstractMethod(object: bird) // Works as bird implements both the protocols
abstractMethod(object: fish) // Compile time error as it does not implement both the protocols

The Delegate Pattern Or Observer Pattern:

A delegate is a common design pattern used in Cocoa and CocoaTouch frameworks, where one class delegates responsibility for implementing some functionality to another. This follows a principle of separation of concerns, where the framework class implements generic functionality while a separate delegate instance implements the specific use case

The delegate pattern using protocol provides us a way to observe for the actions or changes on some objects.

Let’s dive into a more concrete example. if you have two classes, a parent and a child

class Parent { } 
class Child { }

And you want to notify the parent of a change from the child. In Swift, delegates are implemented using a protocol declaration and so we will declare a protocol which the delegate will implement. Here delegate is the parent object.

protocol ChildDelegate: class 
{
func childDidSomething()
}

The child needs to declare a property to store the reference to the delegate:

class Child {
weak var delegate: ChildDelegate?
}

Notice the variable delegate is an optional and the protocol ChildDelegate is marked to be only implemented by class type (without this the delegate variable can’t be declared as a weak reference avoiding any retain cycle. This means that if the delegate variable is no longer referenced anywhere else, it will be released). This is so the parent class only registers the delegate when it is needed and available. Also in order to mark our delegate as weak, we must constrain our ChildDelegate protocol to reference types by adding a class keyword in protocol declaration. In this example, when the child does something and needs to notify its parent, the child will call:

delegate?.childDidSomething()

If the delegate has been defined, the delegate will be notified that the child has done something.

The parent class will need to extend the ChildDelegate protocol to be able to respond to its actions.

This can be done directly on the parent class:

class Parent: ChildDelegate { 
... func childDidSomething() {
print("Yay!")
}
}

Or using an extension:

extension Parent: ChildDelegate { 
func childDidSomething() {
print("Yay!")
}
}

The parent also needs to tell the child that it is the child’s delegate:

// In the parent
let child = Child()
child.delegate = self

Conclusion:

In this chapter, we learned the basics of the protocols usages and advantages of it. Practice it a lot on real-world problems and solve them using protocols instead of Classes. Learn it until I come with the next chapter on it. Goodbye!!!

}

--

--

No responses yet