0
0
iOS Swiftmobile~15 mins

Protocols in iOS Swift - Deep Dive

Choose your learning style9 modes available
Overview - Protocols
What is it?
Protocols in Swift are like blueprints that define a set of methods, properties, or other requirements that a type must implement. They do not provide the actual implementation but specify what should be done. Any class, struct, or enum can adopt a protocol and provide its own implementation for the required parts.
Why it matters
Protocols allow different types to share common behavior without needing to inherit from a common parent. Without protocols, code would be less flexible and harder to reuse, making apps more complex and rigid. They help organize code, enable easier testing, and support powerful design patterns like delegation and abstraction.
Where it fits
Before learning protocols, you should understand basic Swift types like classes, structs, and enums, and how functions and properties work. After mastering protocols, you can explore protocol-oriented programming, delegation patterns, and advanced Swift features like protocol extensions and associated types.
Mental Model
Core Idea
A protocol is a contract that says: 'If you adopt me, you promise to implement these methods and properties.'
Think of it like...
Think of a protocol like a job description. It lists the tasks and skills required for a role, but it doesn't say how to do them. Different people (types) can apply for the job and perform the tasks in their own way.
┌───────────────┐
│   Protocol    │
│───────────────│
│ - methodA()   │
│ - propertyB   │
└──────┬────────┘
       │ adopts
       ▼
┌───────────────┐   ┌───────────────┐
│   Class/Struct│   │   Class/Struct│
│───────────────│   │───────────────│
│ - methodA()   │   │ - methodA()   │
│ - propertyB   │   │ - propertyB   │
└───────────────┘   └───────────────┘
Build-Up - 7 Steps
1
FoundationWhat is a Protocol in Swift
🤔
Concept: Introduces the basic idea of protocols as blueprints for methods and properties.
In Swift, a protocol defines a list of methods and properties that a type must implement. It does not contain the actual code, just the requirements. For example, a protocol named 'Drivable' might require a method 'drive()'.
Result
You understand that protocols describe what a type should do, not how it does it.
Understanding that protocols separate the 'what' from the 'how' is key to flexible and reusable code.
2
FoundationAdopting Protocols in Types
🤔
Concept: Shows how classes, structs, and enums can adopt protocols and implement their requirements.
To adopt a protocol, a type lists it after its name, separated by a colon. Then it must implement all required methods and properties. For example: protocol Drivable { func drive() } struct Car: Drivable { func drive() { print("Car is driving") } }
Result
You can make your own types follow a protocol by implementing its requirements.
Knowing how to adopt protocols lets you create types that share common behavior without inheritance.
3
IntermediateProtocol Properties and Mutability
🤔Before reading on: Do you think protocol properties can be both gettable and settable? Commit to your answer.
Concept: Explains how protocols can require properties to be readable, writable, or both, and how this affects conforming types.
Protocols can require properties to be 'get' only or 'get set'. For example: protocol Named { var name: String { get set } } A conforming type must provide a property that matches this requirement. If the protocol requires 'get set', the property must be mutable.
Result
You understand how to declare property requirements and how they control mutability in conforming types.
Knowing property requirements helps you design protocols that control how data can be accessed or changed.
4
IntermediateProtocol Inheritance and Composition
🤔Before reading on: Can a protocol inherit from multiple protocols? Commit to yes or no.
Concept: Introduces how protocols can inherit from other protocols and how multiple protocols can be combined.
Protocols can inherit from one or more protocols, combining their requirements. For example: protocol Runnable { func run() } protocol Drivable { func drive() } protocol Vehicle: Runnable, Drivable {} A type adopting Vehicle must implement both run() and drive().
Result
You can create complex protocols by combining simpler ones, making your code more modular.
Understanding protocol inheritance and composition allows you to build flexible and reusable abstractions.
5
IntermediateUsing Protocols as Types
🤔Before reading on: Can you use a protocol as a type for variables or function parameters? Commit to yes or no.
Concept: Shows that protocols can be used as types to hold any value that conforms to them.
You can declare variables, constants, or function parameters with a protocol type. For example: func startDriving(vehicle: Drivable) { vehicle.drive() } This function can accept any type that conforms to Drivable.
Result
You can write flexible functions and variables that work with any conforming type.
Using protocols as types enables polymorphism and decouples code from specific implementations.
6
AdvancedProtocol Extensions for Default Behavior
🤔Before reading on: Do you think protocols can provide default method implementations? Commit to yes or no.
Concept: Explains how protocol extensions can add default implementations to protocol methods and properties.
Swift allows you to extend protocols to provide default code. For example: protocol Drivable { func drive() } extension Drivable { func drive() { print("Default driving") } } Types adopting Drivable get this default drive() unless they provide their own.
Result
You can reduce code duplication and add shared behavior to all conforming types.
Knowing protocol extensions lets you write cleaner and more maintainable code by sharing default behavior.
7
ExpertAssociated Types and Generic Protocols
🤔Before reading on: Can protocols have placeholder types that conforming types specify? Commit to yes or no.
Concept: Introduces associated types, which are placeholders for types used inside protocols, enabling generic programming.
Protocols can declare associated types as placeholders. For example: protocol Container { associatedtype Item func append(_ item: Item) var count: Int { get } subscript(i: Int) -> Item { get } } Conforming types specify what 'Item' is. This allows writing flexible, generic code.
Result
You can create protocols that work with any type, making your code highly reusable and abstract.
Understanding associated types unlocks the power of Swift's generic and protocol-oriented programming.
Under the Hood
At runtime, protocols use a mechanism called 'witness tables' to map protocol requirements to the actual implementations in conforming types. This allows Swift to call the correct method or access the right property even when using a protocol type. The compiler generates this mapping during compilation, enabling dynamic dispatch for protocol methods.
Why designed this way?
Protocols were designed to provide flexible abstraction without forcing inheritance hierarchies. This allows Swift to support multiple inheritance of behavior via protocols, while keeping the type system safe and efficient. The witness table approach balances performance with flexibility, avoiding the overhead of full dynamic dispatch used in some other languages.
┌───────────────┐
│ Protocol Type │
└──────┬────────┘
       │
       ▼
┌───────────────┐
│ Witness Table │
│ (Method Map)  │
└──────┬────────┘
       │
       ▼
┌───────────────┐
│ Concrete Type │
│ Implementation│
└───────────────┘
Myth Busters - 4 Common Misconceptions
Quick: Do you think protocols can contain stored properties? Commit to yes or no.
Common Belief:Protocols can have stored properties just like classes or structs.
Tap to reveal reality
Reality:Protocols cannot have stored properties; they can only require properties to be implemented by conforming types.
Why it matters:Trying to add stored properties in protocols leads to compiler errors and confusion about where data should be stored.
Quick: Can a protocol be instantiated directly? Commit to yes or no.
Common Belief:You can create an instance of a protocol just like a class or struct.
Tap to reveal reality
Reality:Protocols cannot be instantiated because they do not provide implementations, only requirements.
Why it matters:Misunderstanding this leads to errors when trying to create protocol instances and confusion about protocol roles.
Quick: Does adopting multiple protocols mean inheriting from multiple classes? Commit to yes or no.
Common Belief:Adopting multiple protocols is the same as multiple inheritance of classes.
Tap to reveal reality
Reality:Protocols provide multiple behavior inheritance but do not inherit implementation like classes; Swift does not support multiple class inheritance.
Why it matters:Confusing protocols with class inheritance can cause design mistakes and misuse of protocols.
Quick: Do protocol extensions override methods implemented in conforming types? Commit to yes or no.
Common Belief:Protocol extension methods always override conforming type methods.
Tap to reveal reality
Reality:Methods implemented in conforming types take precedence over protocol extension defaults.
Why it matters:Misunderstanding this can cause unexpected behavior and bugs when default implementations are ignored.
Expert Zone
1
Protocol extensions can add methods that are only available when the conforming type meets extra constraints, enabling powerful conditional behavior.
2
Using protocols with associated types can complicate type erasure, requiring advanced patterns to work around Swift's type system limitations.
3
Protocols can be combined with generics to create highly abstract and reusable APIs, but this requires careful design to avoid complexity.
When NOT to use
Protocols are not ideal when you need to share stored data or implementation details directly; in such cases, class inheritance or composition might be better. Also, protocols with associated types cannot be used as concrete types without type erasure, so for simple polymorphism, plain protocols without associated types are preferred.
Production Patterns
Protocols are widely used for delegation patterns (e.g., UITableViewDelegate), dependency injection, mocking in tests, and defining interfaces for modular components. Protocol-oriented programming encourages designing apps by composing small protocols and extending them, leading to flexible and testable codebases.
Connections
Interfaces in Object-Oriented Programming
Protocols in Swift serve the same role as interfaces in languages like Java or C#.
Understanding protocols helps grasp how different languages enforce contracts for types, enabling polymorphism and abstraction.
Abstract Base Classes
Protocols provide abstraction without implementation, similar to abstract base classes but without inheritance constraints.
Knowing the difference clarifies when to use protocols versus class inheritance for code reuse and design.
Contracts in Legal Agreements
Protocols are like contracts that specify obligations without dictating how to fulfill them.
This cross-domain view helps appreciate protocols as promises that enable trust and cooperation between different parts of code.
Common Pitfalls
#1Trying to add stored properties inside a protocol.
Wrong approach:protocol Vehicle { var speed: Int = 0 }
Correct approach:protocol Vehicle { var speed: Int { get set } }
Root cause:Misunderstanding that protocols only declare requirements, not storage or implementation.
#2Assuming protocol extension methods override conforming type methods.
Wrong approach:extension Drivable { func drive() { print("Default") } } struct Car: Drivable { func drive() { print("Car") } } // Calling drive() prints "Default"
Correct approach:extension Drivable { func drive() { print("Default") } } struct Car: Drivable { func drive() { print("Car") } } // Calling drive() prints "Car"
Root cause:Not knowing that conforming type implementations take precedence over protocol extension defaults.
#3Using protocols with associated types as concrete types directly.
Wrong approach:var container: Container // Error: Protocol with associated type cannot be used as a type
Correct approach:Use type erasure wrappers or generics to work with protocols with associated types.
Root cause:Not understanding Swift's type system restrictions on protocols with associated types.
Key Takeaways
Protocols define a set of requirements that types promise to implement, enabling flexible and reusable code.
Any Swift type can adopt protocols, allowing shared behavior without inheritance.
Protocol extensions provide default implementations, reducing code duplication and enhancing maintainability.
Associated types in protocols enable generic and abstract designs but require careful handling in code.
Understanding protocols deeply unlocks powerful design patterns and makes your Swift code more modular and testable.