Implementing the Adapter Design Pattern in Swift

Let’s talk about the Adapter design pattern using a real-world example in Swift

Alonso Alvarez
Better Programming

--

Photo by Markus Winkler on Unsplash

Adapter is a structural design pattern that lets incompatible classes or structs work together.

Typically used when we want to integrate an external class/struct or a 3rd party library into our code and their interfaces don't match with the ones we currently use in our application.

Let’s see a common structure for an Adapter implementation:

An Adapter implementation consists of three main actors/participants:

Target Interface (Protocol): Defines the interface that is used by client code across our application. We use the Adapter pattern to make an existing class/struct compatible with our Target Interface.

Adaptee: Defines the type that needs to be adapted to be compatible with the Target Interface.

Adapter: In charge of adapting the Adaptee type to the target interface. This can be implemented using an Adapter type (class or struct implemented as shown in the code from above) or making use of Swift extensions (we will take a look at this approach in the final section).

Real-world example

Let’s imagine we currently have in our application, the following interface which main purpose is to present a progress HUD:

And it is being vastly used across our application like this:

Then, we are assigned a task where we need to start using PKHUD for all of our HUD presentations. Given that most of our screens are currently using HUDPresenter as a dependency, we want to keep using it. So this is a good spot to use the Adapter pattern to adapt PKHUD to our HUDPresenter protocol:

Here, the target would be the HUDPresenter protocol. The Adaptee would be PKHUD. And the PKHUDPresenter class would be the adapter.

You might be asking: Why won’t we just replace HUDPresenter with an instance of PKHUD? There are several reasons:

  1. If in the future, we want to replace PKHUD with another HUD third-party library, we would need to update every view controller using PKHUD with the new library. This is too error-prone and our code would become less maintainable (a UI dependency change would trigger a lot of updates in our codebase).
  2. We would be violating the Open-closed principle that states that classes should be open for extensions but closed for modifications. We should be able to extend the behavior of our view controllers without the need of modifying their source code.
  3. We would be violating the Dependency inversion principle that states that we should depend on abstractions (protocols in Swift) and not on concrete types (value or reference types in Swift).

Swift extension approach

An alternative approach to having a dedicated struct/class that works as an adapter is to extend the Adaptee to conform our target interface protocol.

Going back to the real-world example from above, our solution following this approach would have looked like this:

With the extension approach, we don’t need to create an additional struct/class for our Adapter.

One disadvantage of this approach is that you will need to import the PKHUD dependency when injecting it into the view controllers. This disadvantage can be minimized if your dependencies are created and injected in a centralized way.

And that’s it! I hope this real-world use case for the Adapter pattern can be useful for you and your future projects.

--

--

Passionate iOS Developer. Skilled in Swift and Objective-C. Currently working as an iOS Engineer at Ring.