Post

Protocol oriented programming in Swift 5 - Basics

Don’t start with a class, start with a protocol.

– Apple

About POP

  • Apple introduced the POP concept in Swift 2.0 (WWDC 2015).
  • Other programming languages such as Java, PHP use the keyword “interface”.

What is a Protocol

  • A protocol defines the method, property requirements that need to be implemented by conforming types i.e [Class, Structure and Enum].
  • The protocol only provides a blueprint for the requirements and It can’t be instantiated.

POP Approach

  • Start defining requirements in a Protocol.
  • Advanced features supported by Protocols are:
    • Protocol Inheritance.
    • Protocol Composition.
    • Protocol Extensions.
  • Value-type preferred over Reference-type. Use struct, enum, and tuple instead of Class exclusively.

Protocol Naming

Refer: Swift API Design Guidelines

  • Protocol Name should be in UpperCamelCase.
  • Protocols that describe what something is should read as nouns (e.g. Collection).
  • Protocols that describe a capability should be named using the suffixes able, ible, or ing (e.g. Equatable, ProgressReporting, CustomStringConvertible).

Protocol Example

1
2
3
protocol BaseType {
    var objId: String { get set }
}

Note: Property in protocol must have explicit { get } or { get set } specifier

Create a Class-bound Protocol

1
2
3
protocol BaseType: AnyObject {
    var objectId: String { get set }
}

Conforming to a protocol

1
2
3
struct Box: BaseType {
    var objectId: String
}

Tip: Use auto-completion to add protocol stubs.

Conforming to protocols via extensions

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
struct StudentModel {
    var name: String
    var rollNumber: Int
}

protocol StudentIdentifiable {
    func studentDesc() -> String
}

extension StudentModel: StudentIdentifiable {
    func studentDesc() -> String {
        return "Student name is \(name) and his roll no. is \(rollNumber)"
    }
}
let student1 = StudentModel(name: "Avadhesh", rollNumber: 1)
print(student1.studentDesc())

Polymorphism using protocols

polymorphism is the provision of a single interface to entities of different types.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
protocol Shape {
    var area: Double { get }
    var perimeter: Double { get }
}

struct Circle: Shape {
    let radius: Double
    var area: Double {
        return .pi * radius * radius
    }
    var perimeter: Double {
        return 2 * .pi * radius
    }
}

struct Rectangle: Shape {
    let width: Double
    let height: Double

    var area: Double {
        return width * height
    }

    var perimeter: Double {
        return 2 * (width + height)
    }
}

struct Square: Shape {
    let lengthOfSide: Double

    var area: Double {
        return lengthOfSide * lengthOfSide
    }

    var perimeter: Double {
        return 4 * lengthOfSide
    }
}

var arrayOfShapes = Array<Shape>()
arrayOfShapes.append(Square(lengthOfSide: 10))
arrayOfShapes.append(Rectangle(width: 30, height: 20))
arrayOfShapes.append(Circle(radius: 10))

for shape in arrayOfShapes {
    print("Shape is \(type(of: shape)) of area \(shape.area) and permimeter \(shape.perimeter)")
}

Output:

1
2
3
4
5
Shape is Square of area 100.0 and permimeter 40.0

Shape is Rectangle of area 600.0 and permimeter 100.0

Shape is Circle of area 314.1592653589793 and permimeter 62.83185307179586

Protocol Inheritance

A protocol can be inherited from one or more protocol and the inherited one can have their own requirements on top of it.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
protocol Identifiable {
    var eventType: String { get }
}

protocol Describing: Identifiable {
    var desc: String { get }
}

protocol EventRecording: Describing {}

struct Event: EventRecording,CustomStringConvertible {
    var eventType: String
    var desc: String

    var description: String {
        return "\(eventType) : \(desc)"
    }
}

let homeEvent = Event(eventType: "HomePage", desc: "Logged In Succesfully!!!")
print(homeEvent)

Output:

1
HomePage : Logged In Succesfully!!!

Protocol Composition

Protocol composition lets the type adopt multiple protocols. It allows us to break requirements into multiple protocols instead of inheriting requirements from a single protocol or super-class.

Consider this class hierarchy :

Protocol-Composition-DFD-768x341

Note: Flowchart created with Creately

With Protocol composition, we can have our requirements specified under protocols for Employee, Senior, and Junior. This approach allows us to only adopt to the requirement we desire.

1
struct JuniorJavaDeveloper: EmployeeProtocol, JuniorProtocol { } 
This post is licensed under CC BY 4.0 by the author.