Swift — The Protocol Way — Chapter 2/2

Ankur JAIN
3 min readMar 8, 2019

Introduction

We learned the basic usages of Protocols and Delegate pattern in the first chapter. Now Let’s dive into some other topics in Protocols. If you missed Part 1 of this series, I would suggest you go through it Part 1

Generic Protocols Or Protocols with Associated Type

So why do we need generic type at first place? Let’s look at this example below

//Protocol Associated Types
enum AssetType{
case Computer
case Laptop
case Mobile
case Wifi
}
struct InventoryList<T> {
var items: [T]
mutating func add(item: T) {
items.append(item)
}
mutating func remove() -> T {
return items.removeLast()
}
func isCapacityLow() -> Bool {
return items.count < 3
}
}var inventory = InventoryList<AssetType>(items: [AssetType.Computer, AssetType.Mobile,AssetType.Wifi])

As we can see, with Generics, we can store multiple items to the InventoryList struct. This obviously saves our duplicated code. So how do we take advantage of Generics in Swift? Let’s see

Protocols may define associated type requirements using the associated type keyword:

//Associated Typesprotocol CustomCollection {
associatedtype CustomType
var items: [CustomType] { set get }
mutating func add(item: CustomType)
var size: Int { get }
mutating func removeLast() -> CustomType
}
extension CustomCollection{
mutating func add(item: CustomType) {
items.append(item)
}
mutating func removeLast() -> CustomType{
return items.removeLast()
}
}

A type which conforms to the protocol may satisfy an associated type requirement implicitly, by providing a given type where the protocol expects the associated type to appear:

Or in Simple words, we can say that associatedtype creates a hole for a data type which has to be filled by the conforming class or struct!!!!!!!!!!!!!!!!

Let’s see how we conform to Generic Protocols

struct StringCollection: CustomCollection{
typealias CustomType = String // Optional
var items: [String]
var size: Int
}

CustomType will be considered as String now. It’s that easy!!!

Class Only Protocols

A protocol may specify that only a class can implement it through using the class keyword in its inheritance list. This keyword must appear before any other inherited protocols in this list.

protocol ClassOnlyProtocol: class, CustomCollection { 
// Protocol requirements
}

If a non-class type tries to implement ClassOnlyProtocol, a compiler error will be generated.

struct MyStruct: ClassOnlyProtocol {
// error: Non-class type 'MyStruct' cannot conform to class protocol
'ClassOnlyProtocol'
}

Other protocols may inherit from the ClassOnlyProtocol, but they will have the same class-only requirement.

protocol MyProtocol: ClassOnlyProtocol {
// ClassOnlyProtocol Requirements
// MyProtocol Requirements
}
class MySecondClass: MyProtocol {
// ClassOnlyProtocol Requirements
// MyProtocol Requirements
}

Reference semantics of class-only protocols

Using a class-only protocol allows for reference semantics when the conforming type is unknown

protocol Foo : class {
var bar : String { get set }
}
func takesAFoo(foo:Foo) {
// this assignment requires reference semantics,
// as foo is a let constant in this scope.
foo.bar = "new value"
}

In this example, as Foo is a class-only protocol, the assignment to the bar is valid as the compiler knows that foo is a class type, and therefore has reference semantics.

Protocol extension for a specific conforming class

You can write the default protocol implementation for a specific class.

protocol MyProtocol {
func doSomething()
}
extension MyProtocol where Self: UIViewController {
func doSomething() {
print("UIViewController default protocol implementation")
}
}
class MyViewController: UIViewController, MyProtocol { } let vc = MyViewController() vc.doSomething() // Prints "UIViewController default protocol
implementation"

Implementing Hashable protocol

Types used in Sets and Dictionaries(key) must conform to Hashable protocol which inherits from Equatable protocol.

Custom type conforming to Hashable protocol must implement

  • A calculated property hashValue
  • Define one of the equality operators i.e. == or !=.

Following example implements Hashable protocol for a custom struct:

struct Cell {
var row: Int
var col: Int
init(_ row: Int, _ col: Int) {
self.row = row
self.col = col
}
}
extension Cell: Hashable { // Satisfy Hashable requirement
var hashValue: Int {
get {
return row.hashValue^col.hashValue
}
}
// Satisfy Equatable requirement
static func ==(lhs: Cell, rhs: Cell) -> Bool {
return lhs.col == rhs.col && lhs.row == rhs.row
}
}
// Now we can make Cell as key of dictonary
var dict = [Cell : String]()
dict[Cell(0, 0)] = "0, 0"
dict[Cell(1, 0)] = "1, 0"
dict[Cell(0, 1)] = "0, 1"
// Also we can create Set of Cells
var set = Set<Cell>()
set.insert(Cell(0, 0))
set.insert(Cell(1, 0))

Conclusion

Apple recommends Protocol Oriented Programming over Object Oriented Programming. So it becomes very important for a Swift developer to make use of the protocols in the best way possible.

See you soon with the next story. Bye!!

--

--