DIP: Dependency Inversion Principle in Swift (with code examples) — SOLID Principles

Gizem Türker
3 min readAug 1, 2022

--

Suppose you are in the software ecosystem, no matter what field, S.O.L.I.D. You need to know the principle. We are together in the last article of this series. S.O.L.I.D. You can follow my other articles in this series to learn the concept:

SRP: Single Responsibility Principle in Swift (with code examples) — SOLID Principles

OCP: Open/Closed Principle in Swift (with code examples) — SOLID Principles

LSP: Liskov Substitution Principle in Swift (with code examples) — SOLID Principles

Interface Segregation Principle in Swift (with code examples) — SOLID Principles

What the dependency inversion principle tells us:

High-level modules should not depend upon low-level modules. Both should depend upon abstractions.

Abstractions should not depend upon details. Details should depend upon abstractions.

Why do we need DIP?

We need a loosely coupled code base. By implementing the dependency inversion principle, we create an abstraction between two interacting modules. Both those two interacting modules depend on the conception. In Swift, we achieve the generalization through a protocol.
Following the DIP is provided a clean code, flexibility, and scalability in your stack.

High-level policies represent the logic part of a module, and low-level details represent the implementation part of that module. If we’re confused enough, let’s make things more apparent with an example.
That’s the UITableViewDataSource that we use in UIKit every day, and maybe even though we don’t even know it exists. In reality, every delegation is a DIP case. We use the Dependency Inversion principle in Swift when initializing and implementing the protocol.

How? Why? UITableViewDataSource (my precious :). So what happens by conforming to the UITableViewDataSource delegate? We have to implement two methods tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int and tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell. These two methods ask us about the higher-level logic, like the total number of rows and how the cell will be defined.

As seen above, the Higher level logic[Code base] has a run time dependency on UIKit, but it has no compile time dependency on UIKit. Rather the Higher level logic[Code base] has a compile-time dependency over a protocol, UITableViewDataSource.

(Bad) Example

In the code block below, A high-level module DatabaseController is connected to a low-levelNetworkRequest .

(Better) Example

Here, the protocol is used to escape tight coupling and respect DIP.

Discuss in the comment.

Follow the LinkedIn, Twitter, and Github.

Useful links and Sources:

  1. https://developers.soundcloud.com/blog/dependency-inversion-as-a-driver-to-scale-mobile-development
  2. https://dev.to/kevinmaarek/dependency-inversion-principle-in-swift-1h15
  3. https://clean-swift.com/dependency-inversion-a-little-swifty-architecture/
  4. https://mobidevtalk.com/swift-dependency-inversion-through-protocol/#Why-we-need-the-Dependency-Inversion
  5. https://daddycoding.com/2021/05/30/dependency-inversion-principle/

--

--