Swift Protocols
Defining blueprints of methods and properties
📋 What are Swift Protocols?
Protocols define blueprints of methods, properties, and requirements that classes, structures, or enums can adopt. They enable powerful abstraction and polymorphism, allowing different types to share common behavior and interfaces.
// Basic protocol definition
protocol Drawable {
func draw()
var area: Double { get }
}
struct Circle: Drawable {
var radius: Double
func draw() {
print("Drawing a circle with radius \(radius)")
}
var area: Double {
return .pi * radius * radius
}
}
let circle = Circle(radius: 5.0)
circle.draw() // Output: Drawing a circle with radius 5.0
print("Area: \(circle.area)") // Output: Area: 78.54
Key Protocol Features
Method Requirements
Define required methods
protocol Flyable {
func fly()
func land()
}
Property Requirements
Specify required properties
protocol Named {
var name: String { get set }
var fullName: String { get }
}
Default Implementations
Provide default behavior in extensions
extension Drawable {
func describe() {
print("This shape has area \(area)")
}
}
Protocol Inheritance
Protocols can inherit from other protocols
protocol Shape: Drawable {
var perimeter: Double { get }
}
🔹 Basic Protocol Implementation
Here's how to define and implement a simple protocol:
protocol Vehicle {
var brand: String { get }
var speed: Int { get set }
func start()
func stop()
func accelerate(by amount: Int)
}
struct Car: Vehicle {
let brand: String
var speed: Int = 0
func start() {
print("\(brand) car is starting...")
speed = 10
}
func stop() {
print("\(brand) car is stopping...")
speed = 0
}
func accelerate(by amount: Int) {
speed += amount
print("\(brand) accelerated to \(speed) mph")
}
}
let myCar = Car(brand: "Toyota")
myCar.start()
myCar.accelerate(by: 30)
myCar.stop()
Output:
Toyota car is starting...
Toyota accelerated to 40 mph
Toyota car is stopping...
🔹 Protocol Extensions
Add default implementations to protocols using extensions:
protocol Greetable {
var name: String { get }
func greet()
}
extension Greetable {
func greet() {
print("Hello, I'm \(name)!")
}
func formalGreeting() {
print("Good day, my name is \(name).")
}
}
struct Person: Greetable {
let name: String
}
struct Robot: Greetable {
let name: String
// Override default implementation
func greet() {
print("BEEP BOOP. I AM \(name.uppercased())")
}
}
let person = Person(name: "Alice")
let robot = Robot(name: "R2D2")
person.greet() // Uses default implementation
person.formalGreeting() // Uses extension method
robot.greet() // Uses custom implementation
robot.formalGreeting() // Uses extension method
Output:
Hello, I'm Alice!
Good day, my name is Alice.
BEEP BOOP. I AM R2D2
Good day, my name is R2D2.
🔹 Protocol Inheritance
Protocols can inherit from other protocols to build hierarchies:
protocol Animal {
var name: String { get }
func makeSound()
}
protocol Pet: Animal {
var owner: String { get set }
func play()
}
protocol Trainable: Pet {
var tricks: [String] { get set }
func performTrick(_ trick: String)
}
struct Dog: Trainable {
let name: String
var owner: String
var tricks: [String] = []
func makeSound() {
print("\(name) says: Woof!")
}
func play() {
print("\(name) is playing fetch with \(owner)")
}
func performTrick(_ trick: String) {
if tricks.contains(trick) {
print("\(name) performs \(trick)!")
} else {
print("\(name) doesn't know how to \(trick)")
}
}
}
var myDog = Dog(name: "Buddy", owner: "John")
myDog.tricks = ["sit", "roll over", "fetch"]
myDog.makeSound()
myDog.play()
myDog.performTrick("sit")
myDog.performTrick("dance")
Output:
Buddy says: Woof!
Buddy is playing fetch with John
Buddy performs sit!
Buddy doesn't know how to dance
🔹 Protocol as Types
Use protocols as types for polymorphism:
protocol Playable {
var title: String { get }
var duration: Int { get } // in seconds
func play()
}
struct Song: Playable {
let title: String
let duration: Int
let artist: String
func play() {
print("♪ Playing song: \(title) by \(artist)")
}
}
struct Podcast: Playable {
let title: String
let duration: Int
let host: String
func play() {
print("🎙️ Playing podcast: \(title) hosted by \(host)")
}
}
// Array of protocol types
let playlist: [Playable] = [
Song(title: "Swift Song", duration: 180, artist: "Code Band"),
Podcast(title: "iOS Development", duration: 1800, host: "Tech Guru"),
Song(title: "Protocol Blues", duration: 240, artist: "Swift Singers")
]
func playAll(_ items: [Playable]) {
for item in items {
item.play()
print("Duration: \(item.duration) seconds\n")
}
}
playAll(playlist)
Output:
♪ Playing song: Swift Song by Code Band
Duration: 180 seconds
🎙️ Playing podcast: iOS Development hosted by Tech Guru
Duration: 1800 seconds
♪ Playing song: Protocol Blues by Swift Singers
Duration: 240 seconds
🔹 Protocol Best Practices
Follow these guidelines when working with protocols:
✅ Good Practices:
- Single responsibility: Keep protocols focused on one concept
- Composition over inheritance: Use multiple protocols instead of complex hierarchies
- Default implementations: Provide sensible defaults in extensions
- Meaningful names: Use descriptive protocol names ending in -able, -ing, or -Protocol
💡 When to Use Protocols:
- Defining common behavior across different types
- Creating flexible, testable code through dependency injection
- Building plugin architectures or extensible systems
- Enabling polymorphism without inheritance
- Defining contracts for APIs and frameworks