Swift Protocols
A protocol defines a set of rules — properties and methods — that a type must follow. It does not provide the actual code; it only lists what is required. Any struct, class, or enum that adopts a protocol must implement all its requirements.
The Job Contract Analogy
┌──────────────────────────────────────────────────┐
│ Protocol = A Job Contract │
│ │
│ Contract says: │
│ - Must clock in daily (property) │
│ - Must complete reports (method) │
│ - Must attend weekly meeting (method) │
│ │
│ Every employee who signs the contract │
│ must do all three things. │
│ How they do it is their own choice. │
└──────────────────────────────────────────────────┘
Defining a Protocol
protocol Greetable {
var name: String { get }
func greet() -> String
}
{ get } means the property must be readable. { get set } means it must also be writable. Methods have no body — just their signature.
Adopting a Protocol in a Struct
struct Person: Greetable {
var name: String
func greet() -> String {
return "Hi, I am \(name)!"
}
}
let p = Person(name: "Ananya")
print(p.greet()) // Hi, I am Ananya!
Adopting a Protocol in a Class
class Robot: Greetable {
var name: String
init(name: String) {
self.name = name
}
func greet() -> String {
return "BEEP. I am \(name)."
}
}
let r = Robot(name: "R2D2")
print(r.greet()) // BEEP. I am R2D2.
Both Person and Robot fulfill the same contract but implement it differently. This is the power of protocols.
Multiple Protocol Adoption
protocol Flyable {
func fly()
}
protocol Swimmable {
func swim()
}
struct Duck: Flyable, Swimmable {
func fly() { print("Duck flies.") }
func swim() { print("Duck swims.") }
}
A type can adopt multiple protocols separated by commas. This is how Swift achieves flexibility without the complexity of multiple inheritance.
Protocol as a Type
func makeNoise(for creature: Greetable) {
print(creature.greet())
}
makeNoise(for: Person(name: "Ravi")) // Hi, I am Ravi!
makeNoise(for: Robot(name: "WALL-E")) // BEEP. I am WALL-E.
You can use a protocol as a parameter type. The function works with any type that conforms to Greetable — it does not care whether it is a struct, class, or enum.
Protocol Flow Diagram
┌──────────────────────────────────────────────────────┐
│ Protocol: Greetable │
│ Requires: name (property), greet() (method) │
│ │ │
│ ┌───────────┼───────────┐ │
│ Person Robot Employee │
│ (struct) (class) (struct) │
│ │
│ All three implement their own version of greet() │
│ All three can be used wherever Greetable is needed │
└──────────────────────────────────────────────────────┘
Protocol with Default Implementation (Extensions)
protocol Describable {
var title: String { get }
func describe()
}
extension Describable {
func describe() {
print("This is: \(title)")
}
}
struct Book: Describable {
var title: String
// describe() is NOT required — default is used
}
let b = Book(title: "Swift Essentials")
b.describe() // This is: Swift Essentials
Protocol extensions let you provide a default implementation. Types that adopt the protocol get it for free, but can override it if they need different behaviour.
Commonly Used Swift Protocols
| Protocol | Purpose |
|---|---|
| Equatable | Compare with == |
| Comparable | Compare with <, > |
| Codable | Encode/decode to JSON |
| Hashable | Use in sets and as dict keys |
| CustomStringConvertible | Custom print output |
