When Apple introduced Swift, it also introduced a slogan: “Swift is a protocol-oriented language.” Instead of building deep class hierarchies, you describe capabilities with protocols, give them default behavior with extensions, and let any type, whether a struct, an enum, or a class, adopt exactly the capabilities it needs.
Most of the Swift standard library works this way, from Equatable and Hashable to Sequence and Collection. This guide shows how to use the same approach in your own code.
Article available Coming soon
1. Why Not Just OOP?
An OOP Refresher Before Protocol-Oriented Swift
Protocol-oriented programming is easier to understand when the object-oriented ideas underneath it are clear. Encapsulation, abstraction, and polymorphism still matter when the...
The Limits of Class Inheritance in Swift
Inheritance is useful when a subclass is a behavioral specialization of its superclass. It becomes restrictive when the hierarchy is used to...
OOP vs. POP in Swift: Two Ways to Share Behavior
Object-oriented and protocol-oriented programming overlap in Swift. Both can hide implementation details, protect state, and let consumers work with interchangeable behavior. The...
2. Protocol Basics
Protocols in Swift
A protocol describes what a type can do, without saying how. Classes, structs, and enums can all adopt protocols, which makes them...
Property and Method Requirements in Swift Protocols
A protocol requirement is a promise a consumer can rely on. A property requirement controls which access is available through the interface;...
Adopting Swift Protocols in Structs, Enums, and Classes
A protocol describes a capability; conformance connects a concrete type to that capability. Structs, enums, and classes can all conform, but they...
Protocols Instead of Multiple Inheritance in Swift
A downloadable report may be identifiable, serializable, and shareable. Those capabilities do not require three parent classes. Swift classes have at most...
Class-Only Protocols in Swift: AnyObject and Ownership
Adding AnyObject to a protocol restricts its conformers to class instances. That restriction is useful when reference identity, weak relationships, or shared...
3. Protocol Extensions
Default Implementations in Swift Protocol Extensions
A default implementation lets conforming types share behavior without sharing a superclass. Its usefulness depends on a precise distinction: implementing a protocol...
Extensions in Swift
Extensions add new functionality to an existing type, even one you don’t own, like Int, String, or URL. They’re also how Swift...
Constrained Protocol Extensions in Swift: Make the Requirement Visible
A constrained extension makes an operation available only when the compiler can establish the extra facts that operation needs. It can add...
Static vs. Dynamic Dispatch in Swift
When your code calls a method, the program has to decide which implementation runs. Sometimes the compiler knows at compile time: that’s...
4. Protocols and Generics
Generics in Swift
Generics let you write code once and use it with many types, without giving up type safety. Array<Element>, Dictionary<Key, Value>, Optional<Wrapped>, and...
Associated Types in Swift: Preserve Relationships Between Capabilities
An associated type lets each protocol conformance choose a related concrete type. It is useful when the capability’s operations must agree about...
Primary Associated Types in Swift: Keep the Useful Type Information
Primary associated types make an associated type convenient to constrain at a protocol’s use site. They let an API say any ItemLoading<String>...
Protocol Inheritance in Swift: Refine Capabilities Without Sharing Storage
Protocol inheritance combines requirements. A refined protocol can demand everything its parent demands and add another capability or a stronger associated-type constraint....
Opaque and Boxed Types in Swift: some vs. any
some View is in every SwiftUI file, and any Error is in most error-handling code. Both keywords put a protocol where a...
Phantom Types in Swift
Phantom types let you tuck extra meaning into Swift’s type system without changing anything at runtime. A phantom type is a generic...
5. Errors and Protocols
Error Handling in Swift
Things go wrong: files are missing, networks drop, users type nonsense. Swift handles recoverable errors with throw, try, and catch, a model...
Typed Throws in Swift 6: Carry Error Types Through Protocols
Swift 6 lets a throwing function name its error type: throws(ParseFailure). This is useful when a capability has a deliberate failure vocabulary...
Designing Error Handling Around Swift Protocols
A protocol abstracts behavior only if its failure semantics are useful to its consumers. A method named load that leaks arbitrary server...
6. Design Patterns, the Protocol Way
Delegation in Swift: One Object Reporting to Another
A picker knows which item the user selected. The screen that owns the picker knows what that selection means for the application....
The Observer Pattern in Swift: Subscriptions, Ordering, and Cancellation
An observer API is a delivery contract, not merely an array of closures. Callers need to know who retains a subscription, whether...
Factories in Protocol-Oriented Swift: Construct the Right Capability
A factory decides how to construct a useful object or value. In protocol-oriented Swift, it can return a capability rather than expose...
Composition Over Inheritance in Swift
A class hierarchy is tempting when two features share behavior. But “uses the same behavior” is weaker than “is a valid kind...
Dependency Injection in Swift Without a Container
A feature is difficult to test when it secretly reads the clock, opens a database, or creates its own network client. Dependency...
7. Putting It Into Practice
Build a Small Reading-List App with Protocol-Oriented Swift
A useful protocol-oriented example should do more than print two interchangeable greetings. It should own state, reject invalid input, perform a replaceable...
Refactoring a Swift Class Hierarchy into Protocols
A useful refactor changes where behavior lives while preserving what callers can observe. Replacing class with protocol is not enough: initialization, shared...
Test Doubles In Swift
The term test doubles draws inspiration from stunt doubles in the movie industry, where a stunt double steps in to perform dangerous...
Performance Considerations for Protocol-Oriented Swift
A protocol declaration has no universal performance penalty. Runtime cost depends on how values cross the boundary, what information the optimizer can...
When Protocols Are Overkill in Swift
A protocol is useful when it expresses a capability a consumer needs to abstract. It is unnecessary when it adds a new...
Up next
Functional Programming