top of page

Building an iOS app with Clean Architecture

We’ve built the core business layer of our app as a Swift package following Clean Architecture principles, so what does it look like to actually use it to build an iOS app?


In today’s post we will look at exactly that, and how our use cases are utilized by client code to build a functional iOS app.


In case you haven’t already, head over to our previous article to learn the basics of Clean Architecture and to see how we use it to build a Swift Package containing our app’s business logic.


You can view the entirety of the iOS app code from this post on GitHub: https://github.com/obvios/employee-directory-mobile-app

The Persistence Layer of our iOS App


If you’ll recall from our previous blog post, when developing our use cases, we had to abstract where the Employee data came from. To accomplish this we defined an EmployeeRepository protocol which our use cases depended on for retrieving Employee data.


This abstraction along with the use cases allowed us to build our core business layer code as a separate Swift Package and solely focus on the business rules, not having to worry about details such as whether data comes from a local file or the network.


However, now that we are building an iOS app, it does matter where this data is coming from. Our use cases still don’t care, but since we are now developing the outer layers, namely the persistence/db layer in this case, this detail does matter.



We are now at the outer layers of clean architecture which are responsible for data persistence, so they must know how data is retrieved and saved. This is where we will create a concrete implementation of the EmployeeRepository protocol.


Below is our implementation. We use a local json file as our persistent storage. It is where we will retrieve employee data and store new data.

With our concrete implementation of the EmployeesRepository protocol, we are ready to move on to the next step.


The UI Layer in SwiftUI


We have our business and persistence layers developed, so the final layer we need to develop in order to complete our iOS app is the UI. This is what users will actually see and directly interact with.



In this specific example of the Employees list view you will notice that we did not use any Presenter objects; we skip over the Presenters layer. It is not absolutely required, but could be useful as the app grows.

For our example we have chosen to use SwiftUI, although we could have just as easily chosen UIKit - that is the beauty of following Clean Architecture, it doesn’t matter. Our EmployeeDirectoryCore Swift Package can continue to grow independently of the iOS app, no matter which framework we choose.


For now, we are going to be using SwiftUI, so let's see what that will look like. Below is our SwiftUI view for the Employee list screen. It utilizes the FetchEmployeeListUseCase to retrieve a list of Employee objects and displays them.

The above SwiftUI view is by no means production ready, it doesn't display errors nor is it pretty, it's only meant to serve as an example. Also note that the .task modifier is attached to the List view, this way data is refreshed when ever the List view appears. This is for demonstration purposes only and not the cleanest solution.

Notice that since our FetchEmployeeListUseCase also supports searching, we reuse it when users submit a search term via the UI. If you recall, this was one of our business rules for the employees list, it had to display all employees and be searchable.


Tying it all together for a functional iOS app using Clean Architecture


Now that we have implemented our data persistence code and our view code, we simply tie everything together in our ContentView by creating an instance of LocalFileEmployeesRepository and inject it into our EmployeeListView. We can now run and build our code to see the following:



I would like to highlight the ease in which we can change how we get and store employee data. Right now we get it from a local file store, but imagine if we want to store that data on a server instead so it can be accessed from anywhere. All we would need to do is create an implementation of EmployeesRepository that uses one of our APIs via the network, then inject that object instead. All other code remains unaffected!


Most importantly, our business logic remains unaffected and can continue being focused on business objectives. Any updates to our business functionality will required an update in our iOS app code, which makes sense since it's how users interact with our logic. However, any updates to SwiftUI or how we persist data, do not affect the inner layers containing our business rules. Which again, makes complete sense, those are simply platform specific details that should not change our business logic.


Conclusion


The example I have highlighted in this blog post is quite simple, but it helps demonstrate how we can architect applications that serve business objectives so that they can scale and support growing teams. Clean Architecture is not that complicated, I think of it as a set of principles that serve as a guide for how to separate your components, as we have seen in this post.


If you have any questions or concerns, please do not hesitate to reach out using my contact form! You can also subscribe to our newsletter to get insights and the latest news related to iOS development by clicking the button below.



bottom of page