SwiftUI in Clean Architecture

Mykola Fiantsev
3 min readDec 21, 2020

--

Clean Architecture diagram from https://commons.wikimedia.org/

I was building an iOS app with a reactive approach before it became mainstream. UI is the function from data, unidirectional data flow, Onion Architecture, and all other words that used to drive some of my colleagues crazy. 2019 has changed this. SwiftUI with Combine are powerful tools that Apple brought to us and nowadays more and more developers find themselves on this road.

I don’t want to dive into a discussion about the Clean Architecture, reactive approach, or MVVM — all of this just works for me. Maybe it will work for you too, maybe won’t. But we should talk in case we’re in the same boat.

As early adopters of new technologies each of us faced some issues walking on the uncharted road, but exactly this feeling makes the journey more enjoyable. This article is not a silver bullet but a step towards the discussion about where I am now and a hope that as a strong community we will find a good approach together. Let’s get started.

The idea of Clean Architecture is dividing the software into layers. (Clean Architecture by Robert C. Martin aka Uncle Bob). In case you are not familiar with this, I highly recommend taking a look. Otherwise, it will be a little bit difficult to catch all of the abstractions I will talk about.

Basically it looks something like this

View Model takes the composition of use cases for initialization. Use Case ⏤ is a protocol with only one concrete purpose method (e.g. observe user, save the document, etc); works with Domain Entities. Repositories are the implementation of Use Cases, operating with Platform Entities.

Usually, it is convenient to implement the Use Cases in Protocol Oriented way and don’t care what actual implementation of repositories are. Whatever responsible for store the document will be able to save it.

It works for me in the UIKit world with the stack: MVVM-RxSwift-DIP. DIP is a simple Dependency Injection Container, it provides rich functionality for DI containers such as auto-wiring, scopes, storyboards integration, etc. All of this helps me to be focused on a particular piece of responsibility and don’t care about the big picture.

Since SwiftUI rolled out I’d like to adopt this approach and keep all its benefits. But what is different in the SwiftUI world?

In addition to a bunch of different changes, the existence of Environment property wrappers was introduced. It allows us to inject arbitrary values into the environment so we don’t need storyboard integration anymore. It sounds like I don’t need third-party DI at all. Let’s try to take advantage of this.

We will define AppEnvironment, which will hold DIContainer with repositories as a property and make this DIContainer EnvironmentKey to get its value whenever we need it.

The implementation of Repositories is just a basic example here. You free to go implement it in any way to achieve weak retaining to destroy the instances you don’t need and all other improvements.

Next step, I’d like to generalize the boilerplate of initialization of ViewModel and subsequent initialization of View with this ViewModel something like this:

Now the creation of the View body looks short, easy to read, and brings nothing annoying to our sight. Cool.

Summary

As I said before this article isn’t a silver bullet with a unique approach rather an invite to the discussion in attempting to build a clear approach to build SwiftUI views. Because all I saw before looks quite messy, usually limited with Single State App approach and violate the separation of concern principle sometimes.

I put my code on GitHub. So if you have some ideas about improving it ⏤ welcome to join.

--

--