Labs ICT
โญ Pro Login

Protocols

Defining contracts for types.

Protocols in Swift

Protocols are blueprints that define what methods, properties, and other requirements a type must have. They don't provide implementations โ€” they just describe the contract. Any type (struct, class, or enum) can conform to a protocol by implementing its requirements.

protocol Describable {
    func describe() -> String
}

struct Car: Describable {
    var make: String
    var model: String
    
    func describe() -> String {
        return "\(make) \(model)"
    }
}

let myCar = Car(make: "Tesla", model: "Model 3")
print(myCar.describe()) // Tesla Model 3
Try it Yourself ->

Protocol Requirements

Protocols can require specific properties and methods. Properties must specify whether they're gettable ({ get }) or gettable and settable ({ get set }). Methods are declared without a body โ€” just the signature.

protocol Vehicle {
    var speed: Double { get set }
    var isRunning: Bool { get }
    func start()
    func stop()
}

struct Bicycle: Vehicle {
    var speed: Double = 0
    var isRunning: Bool = false
    
    mutating func start() {
        isRunning = true
        print("Pedaling!")
    }
    
    mutating func stop() {
        isRunning = false
        speed = 0
        print("Stopped")
    }
}
Try it Yourself ->

Protocol Inheritance

Protocols can inherit from other protocols, extending the requirements. A type that conforms to the child protocol must implement all requirements from both the child and parent protocols.

protocol Named {
    var name: String { get }
}

protocol Aged {
    var age: Int { get }
}

protocol Person: Named, Aged {
    func introduce()
}

struct Student: Person {
    var name: String
    var age: Int
    
    func introduce() {
        print("Hi, I'm \(name) and I'm \(age) years old.")
    }
}

let student = Student(name: "Alice", age: 20)
student.introduce() // Hi, I'm Alice and I'm 20 years old.
Try it Yourself ->

Protocol Extensions

Protocol extensions let you provide default implementations for protocol requirements. This means conforming types don't have to implement everything from scratch โ€” they get the default behavior for free and can override it if needed.

protocol Greetable {
    var name: String { get }
}

extension Greetable {
    func greet() -> String {
        return "Hello, my name is \(name)!"
    }
}

struct Person: Greetable {
    var name: String
    // No need to implement greet() โ€” the extension provides it
}

let person = Person(name: "Alice")
print(person.greet()) // Hello, my name is Alice!
Try it Yourself ->

Standard Protocols

Swift comes with many built-in protocols that provide useful functionality. Equatable lets you compare instances with ==, Comparable lets you sort instances, and Codable lets you encode and decode instances to and from JSON.

struct Score: Comparable {
    let player: String
    let points: Int
    
    static func < (lhs: Score, rhs: Score) -> Bool {
        return lhs.points < rhs.points
    }
}

let scores = [
    Score(player: "Alice", points: 85),
    Score(player: "Bob", points: 92),
    Score(player: "Charlie", points: 78)
]

let sorted = scores.sorted()
for score in sorted {
    print("\(score.player): \(score.points)")
}
// Charlie: 78
// Alice: 85
// Bob: 92
Try it Yourself ->

Why Protocols Matter

Protocols are central to Swift's design philosophy. They let you write flexible, reusable code by programming to an interface rather than a concrete type. Protocol-oriented programming (POP) is a powerful paradigm that Swift embraces wholeheartedly.

protocol Drawable {
    func draw()
}

func renderShapes(_ shapes: [Drawable]) {
    for shape in shapes {
        shape.draw()
    }
}

struct Circle: Drawable {
    func draw() { print("Drawing a circle") }
}

struct Square: Drawable {
    func draw() { print("Drawing a square") }
}

let shapes: [Drawable] = [Circle(), Square(), Circle()]
renderShapes(shapes)
// Drawing a circle
// Drawing a square
// Drawing a circle
Try it Yourself ->

๐Ÿงช Quick Quiz

What does a protocol define?