SWIFT

Swift Protocol: Syntax, Usage, and Examples

A Swift protocol defines a blueprint of methods, properties, and other requirements that classes, structures, and enumerations must adopt. Protocols let you define shared functionality without requiring inheritance, making them a key part of protocol-oriented programming in Swift.

How to Use Protocols in Swift

To define a protocol, use the protocol keyword, then list the required properties and methods. Any type that conforms to the protocol must implement these requirements.

protocol Greetable {
    var name: String { get }
    func greet()
}

struct Person: Greetable {
    var name: String

    func greet() {
        print("Hello, my name is \(name).")
    }
}

let john = Person(name: "John")
john.greet() // Output: Hello, my name is John.

Here, Greetable is a Swift protocol that requires a name property and a greet method. The Person struct conforms to the protocol by implementing both.

Protocol Properties

Protocols define protocol properties in Swift that conforming types must provide. These can be read-only ({ get }) or read-write ({ get set }).

protocol Vehicle {
    var speed: Int { get set }
    var capacity: Int { get }
}

Protocol Methods

Protocols can define methods without providing an implementation. Any type conforming to the protocol must implement these methods.

protocol Drivable {
    func start()
    func stop()
}

class Car: Drivable {
    func start() {
        print("Car is starting...")
    }

    func stop() {
        print("Car is stopping...")
    }
}

When to Use Protocols in Swift

Standardizing Behavior

Protocols help define a standard behavior across multiple types without forcing them into a class hierarchy.

protocol Flyable {
    func fly()
}

struct Bird: Flyable {
    func fly() {
        print("The bird is flying.")
    }
}

struct Plane: Flyable {
    func fly() {
        print("The plane is flying.")
    }
}

Creating Flexible Code

You can use protocol-oriented programming in Swift to make your code more flexible by defining shared behavior that multiple unrelated types can adopt.

protocol Storable {
    func save()
}

class Document: Storable {
    func save() {
        print("Saving document...")
    }
}

class Image: Storable {
    func save() {
        print("Saving image...")
    }
}

Supporting Delegation

Protocols are commonly used for delegation, allowing one object to pass responsibility to another.

protocol DownloadDelegate {
    func didFinishDownloading()
}

class Downloader {
    var delegate: DownloadDelegate?

    func download() {
        print("Downloading...")
        delegate?.didFinishDownloading()
    }
}

class ViewController: DownloadDelegate {
    func didFinishDownloading() {
        print("Download complete!")
    }
}

let vc = ViewController()
let downloader = Downloader()
downloader.delegate = vc
downloader.download()
// Output:
// Downloading...
// Download complete!

Examples of Protocols in Swift

Using a Protocol with an Array

You can store different types in an array as long as they conform to the same protocol.

protocol Animal {
    func makeSound()
}

struct Dog: Animal {
    func makeSound() {
        print("Woof!")
    }
}

struct Cat: Animal {
    func makeSound() {
        print("Meow!")
    }
}

let animals: [Animal] = [Dog(), Cat()]
animals.forEach { $0.makeSound() }
// Output:
// Woof!
// Meow!

Extending Protocols

A Swift protocol extension allows you to add default implementations for protocol methods.

protocol Identifiable {
    var id: String { get }
}

extension Identifiable {
    func identify() {
        print("My ID is \(id).")
    }
}

struct User: Identifiable {
    var id: String
}

let user = User(id: "123")
user.identify() // Output: My ID is 123.

Using Generics with Protocols

A Swift generic protocol allows you to define flexible and reusable code that works with multiple types.

protocol Storage {
    associatedtype Item
    func store(_ item: Item)
}

class Box<T>: Storage {
    typealias Item = T
    func store(_ item: T) {
        print("Storing \(item)")
    }
}

let intBox = Box<Int>()
intBox.store(42) // Output: Storing 42

Protocol Inheritance

A protocol can inherit from one or more protocols using a comma-separated list.

protocol Movable {
    func move()
}

protocol Stoppable {
    func stop()
}

protocol Vehicle: Movable, Stoppable {}

class Bicycle: Vehicle {
    func move() {
        print("Bicycle is moving.")
    }

    func stop() {
        print("Bicycle is stopping.")
    }
}

let bike = Bicycle()
bike.move() // Output: Bicycle is moving.
bike.stop() // Output: Bicycle is stopping.

Learn More About Protocols in Swift

Class-Only Protocols

You can restrict a protocol to class-only types using AnyObject.

protocol ViewControllerDelegate: AnyObject {
    func didUpdate()
}

Optional Protocol Methods

Swift doesn't support optional protocol methods directly, but you can work around this using @objc and optional.

@objc protocol OptionalProtocol {
    @objc optional func optionalMethod()
}

Protocol vs. Class

  • Protocols allow multiple types to share behavior without inheritance.
  • Classes enforce a strict hierarchy where child classes inherit from a parent.
  • Use protocols when defining behavior that multiple unrelated types should conform to.
  • Use classes when modeling relationships where objects need shared state and behavior.

Protocol-Oriented Programming vs. Object-Oriented Programming

  • Object-Oriented Programming (OOP) relies on classes and inheritance.
  • Protocol-Oriented Programming (POP) promotes composition over inheritance, leading to more modular and testable code.

Using Protocols in Real-World Projects

Protocols are widely used in SwiftUI, UIKit, and networking. You often see them in delegate patterns, custom UI components, and dependency injection.

Example: Networking with a Protocol

protocol NetworkService {
    func fetchData(from url: String)
}

class APIClient: NetworkService {
    func fetchData(from url: String) {
        print("Fetching data from \(url)")
    }
}

let apiClient: NetworkService = APIClient()
apiClient.fetchData(from: "https://example.com")
// Output: Fetching data from https://example.com

Best Practices for Using Protocols in Swift

  • Use protocols instead of inheritance when possible. They make your code more flexible and reusable.
  • Define small, focused protocols. Avoid protocols with too many responsibilities.
  • Use protocol extensions to provide default implementations.
  • Avoid forcing class inheritance unless necessary. Use protocol-oriented programming when structuring your app.
  • Prefer composition over inheritance. Instead of creating deep class hierarchies, break functionality into separate protocols.