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 ->