Lesson 73Protocols

Protocol Inheritance

Protocol Inheritance

Protocols can inherit from one or more other protocols, adding new requirements on top. This creates powerful, composable interfaces!

Inheritance Syntax

protocol Child: Parent1, Parent2 {
    // Additional requirements
}

Key Concepts

Multiple Inheritance

Protocols can inherit from many protocols

protocol C: A, B { }

Protocol Composition

Combine protocols with &

func f(_ p: A & B)

Typealias

Name composed protocols

typealias AB = A & B

Conformance Check

Check with is/as

if obj is Protocol

Protocol Composition

Use & to require multiple protocols:

func process(_ item: Codable & Identifiable)

The parameter must conform to BOTH protocols!

Hierarchy Example

Vehicle
├── LandVehicle
├── WaterVehicle
└── AmphibiousVehicle (both)
main.swift
// PROTOCOL INHERITANCE
// Protocols can inherit from other protocols

// SINGLE INHERITANCE
protocol Named {
    var name: String { get }
}

protocol Aged {
    var age: Int { get }
}

// Inheriting from single protocol
protocol Identifiable: Named {
    var id: String { get }
}

// MULTIPLE INHERITANCE
// Protocols can inherit from multiple protocols
protocol Person: Named, Aged {
    var occupation: String { get }
}

struct Employee: Person {
    var name: String
    var age: Int
    var occupation: String
}

let employee = Employee(name: "Alice", age: 30, occupation: "Developer")
print("\(employee.name), \(employee.age), \(employee.occupation)")

// PROTOCOL COMPOSITION
// Combine protocols temporarily with &
func greet(person: Named & Aged) {
    print("Hello \(person.name), you are \(person.age) years old")
}

greet(person: employee)  // Works because Employee conforms to both

// USING TYPEALIAS FOR COMPOSITION
typealias PersonInfo = Named & Aged

func printInfo(_ info: PersonInfo) {
    print("\(info.name) is \(info.age)")
}

// BUILDING PROTOCOL HIERARCHIES
protocol Drawable {
    func draw()
}

protocol Colorable {
    var color: String { get }
}

protocol Shape: Drawable, Colorable {
    var area: Double { get }
}

struct Circle: Shape {
    var radius: Double
    var color: String

    var area: Double {
        return Double.pi * radius * radius
    }

    func draw() {
        print("Drawing a \(color) circle with area \(area)")
    }
}

// SPECIALIZED PROTOCOLS
protocol Vehicle {
    var speed: Int { get }
    func move()
}

protocol LandVehicle: Vehicle {
    var wheels: Int { get }
}

protocol WaterVehicle: Vehicle {
    var draft: Double { get }  // How deep in water
}

protocol AmphibiousVehicle: LandVehicle, WaterVehicle {
    func switchMode()
}

struct Hovercraft: AmphibiousVehicle {
    var speed: Int
    var wheels: Int = 0
    var draft: Double

    func move() {
        print("Hovering at \(speed) mph")
    }

    func switchMode() {
        print("Switching between land and water mode")
    }
}

// CLASS-ONLY PROTOCOL INHERITANCE
protocol ViewControllerDelegate: AnyObject {
    func didLoad()
}

protocol TableViewDelegate: ViewControllerDelegate {
    func didSelectRow(at index: Int)
}

// Implementation must be a class
class MyTableDelegate: TableViewDelegate {
    func didLoad() {
        print("View loaded")
    }

    func didSelectRow(at index: Int) {
        print("Selected row \(index)")
    }
}

// CHECKING PROTOCOL CONFORMANCE
let shape: Any = Circle(radius: 5, color: "red")

if let drawable = shape as? Drawable {
    drawable.draw()
}

if shape is Shape {
    print("It's a shape!")
}

Try It Yourself!

Create a protocol hierarchy for a media app: PlayableAudioPlayable and VideoPlayableStreamableMedia (combines both)!