Protocols in Swift

Introduction

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

Protocol syntax 

 
You can define protocols in a similar way as classes, structures, and enumeration. 
  1. protocol SomeProtocol{  
  2.   // Protocol definition here  
  3. }  
Where class, structures, and enumeration adopt the particular protocol by placing protocol after the type's name, separated by a colon. Multiple protocols can be listed and separated by commas.
  1. struct SomeStructure : FirstProtocol, AnotherProtocol{  
  2.     //Structure definition goes here 
  3. }  

Property requirement

 
A protocol doesn't specify whether the property should be the stored or computed property. It only specifies the required property name and type. The protocol also specifies whether each property must be 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}.
 
  1. protocol SomeProtocol{  
  2.     var mustBeSettable: Int {get, set }  
  3.     var doesNotNeedToBeSettable: Int { get }  
  4. }  
An example of a Protocol with single instance property requirement is given below. 
  1. protocol FullyNamed {  
  2.    var fullName : String { get }  
  3. }  
Example -  
  1. protocol FullyNamed{  
  2.     var fullName: String { get }  
  3.     var Address: String { get }  
  4. }  
  5. struct Person : fullyNamed {  
  6.     var fullName: String  
  7.     var Address: String  
  8. }  
  9. let pravesh = Person(fullName:"Pravesh Dubey", Address:"New Delhi")  
  10.   
  11. print(pravesh.fullName)  
  12. Output: Pravesh Dubey  
  13.  
  14. print(pravesh.Address)  
  15. Output: New Delhi  
The above example defines a structure called Person which represents a specifically named person and their address. It states that the "fullNamed" protocol is a part of the first line of its definition.
 

Method Requirements 

 
Protocols can require specific instance methods and type method to be implemented by conforming types. These methods are written as a part of the protocol's definition in exactly the same way as for normal instance and type methods but without curly braces or method body. Variadic parameters are allowed, subject to the same rules as for normal methods. Default values can't be specified for method parameters within a protocol's definition.
 
The following example defines a protocol with a single instance method requirement - 
  1. protocol RandomNumberGenerator {  
  2.    func random() -> Double  
  3. }  
Here 's is the implementation of a class that adopts and conforms to the "RandomNumberGenerator" protocol.
 
Example -  
  1. protocol RandomNumberGenerator {  
  2.    func random() -> Double  
  3. }  
  4. class LinearCongruentialGenerator : RandomNumberGenerator{  
  5.     var lastRandom = 42.0  
  6.     let m = 139968.0  
  7.     let a = 3877.0  
  8.     let c = 29573.0  
  9.       
  10.     func random() -> Double {  
  11.         lastRandom = ((lastRandom * a + c).truncatingRemainder(dividingBy:m))  
  12.         return lastRandom/m  
  13.     }  
  14. }  
  15. let linear = LinearCongruentialGenerator()  
  16. print(linear.random())  

Mutating Method Requirements 

 
Sometimes we feel it necessary for the method to modify or mutate the instance it belongs to. 
 
For instance, for method on value types (structures and enumeration), you place "mutating" keyword before the method's func. The keyword indicates that the method is allowed to modify the instance it belongs to and properties of that instance.
 
Note
If you mark protocol instance method requirement as mutating, you don't need to write the mutating keyword when writing an implementation of that for a class. The mutating keyword is used only Structure and enumeration.
 
Example
  1. protocol Togglable{  
  2.     mutating func toggle()  
  3. }  
  4. enum OnOffSwitch: Togglable{  
  5.     case off, on  
  6.     mutating func toggle() {  
  7.         switch self {  
  8.         case .off:  
  9.             self = .on  
  10.         case .on:  
  11.             self = .off  
  12.         }  
  13.     }  
  14. }  
  15. var lightSwitch = OnOffSwitch.off  
  16. lightSwitch.toggle()  
  17. // lightSwitch is now equal to .on”  

Protocol as a Type

 
Protocol doesn't actually implement any functionality themselves, you can use a protocol in many places where other types are allowed, including following below -
  • As a parameter type or return type in function, methods or initializer.
  • As a type of constant, variable, property.
  • As a type of items in an Array, dictionary, or other containers. 
Note
Protocols are types, begin their names with a capital letter (such as above example FullyNamed and RandomNumberGenerator) to match the names of other types in Swift (such as Int, String, Double)
 
Example
  1. class Dice {  
  2.     let sides: Int  
  3.     let generator: RandomNumberGenerator  
  4.     init(sides: Int, generator: RandomNumberGenerator) {  
  5.         self.sides = sides  
  6.         self.generator = generator  
  7.     }  
  8.     func roll() -> Int {  
  9.         return Int(generator.random() * Double(sides)) + 1  
  10.     }  
  11. }  
  12.   
  13. let d6 = Dice(sides: 6, generator: LinearCongruentialGenerator())  
  14.   
  15. for _ in 1...5 {  
  16.     print("Random dice number",d6.roll())  
  17. }  
  18.   
  19. Output:   

  20. Random dice number 3  
  21. Random dice number 5  
  22. Random dice number 4  
  23. Random dice number 5  
  24. Random dice number 4

Protocol Inheritance

 
A protocol inheritance can inherit one and more other protocols and can add further requirements on top of requirements it inherits.
 
The syntax for protocol inheritance is similar to the syntax for class inheritance, but with the option to the multiple inherited protocols, separated by commas -
  1. protocol InheritingProtocol: SomeProtocol, AnotherProtocol{  
  2.    // Protocol definition  
  3. }  
Above Example, Suppose there is a struct which is conforming an "InheritingProtocol", it should also conform and satisfy all the other protocols that inheriting protocols inherits from.
 

Protocol Extension 

 
You can extend an existing type to adopt and conform to the new protocol, even if you don't have access to the source code for the existing type. Extention can add new properties, methods, and subscripts to an existing type.
 
 

Class-Only Protocols 

 
You can limit protocol adoption to class types(not structures and enumerations) by adding the AnyObject Protocol to the protocol's inheritance list. Since Swift 4 the preferred way to declare a class-only is to use AnyObject rather than class.
 
You can write like this,
  1. protocol UpdateProfileDelegate: AnyObject {    
  2.   func didFinishTask(sender: UpdateProfileViewController)    
  3.   
  4. //The delegate that adopts the protocol must be a class.  
  5.   
  6. class UpdateProfileViewController: UIViewController {  
  7.   weak var delegate: UpdateProfileDelegate?  
  8. }  
  9. extension UpdateProfileViewController: UpdateProfileDelegate {  
  10.   func didFinishTask(sender: UpdateProfileViewController) { ... }  
  11. }  
Above example can be adopted by only class type, we can't adopt on structure and enumeration, if you trying to adopt, you will get compile time error.  
 

Protocol Composition

 
It can be useful to require a type to conform to multiple protocols at the same time. you can combine multiple protocols into a single requirement with a protocol composition.
 
Protocol composition behaves as if you defined a temporary local protocol that has combined requirements of all protocols in the composition. Protocol composition doesn't define new protocol types.
 
Example
  1. protocol Named {  
  2.     var name: String { get }  
  3. }  
  4. protocol Aged {  
  5.     var age: Int { get }  
  6. }  
  7. struct Person: Named, Aged {  
  8.     var name: String  
  9.     var age: Int  
  10. }  
  11. func wishHappyBirthday(to celebrator: Named & Aged) {  
  12.     print("Happy birthday, \(celebrator.name), you're \(celebrator.age)!")  
  13. }  
  14. let birthdayPerson = Person(name: "Ayush Dubey", age: 12)  
  15. wishHappyBirthday(to: birthdayPerson)  
  16. // Prints "Happy birthday, Ayush Dubey, you're 12!"  

Summary

 
I hope you understood what is all about protocols and in how many ways you define a protocol in Swift. Happy Reading,Enjoy!!
 
If you enjoyed the reading my article, please share it and recommend to others. Thank you in advance.