top of page

Simplify SwiftUI Views Using View Models: Step-by-Step for Beginners

Writer's picture: Eric PalmaEric Palma

Updated: Jan 7

SwiftUI makes building user interfaces easier than ever, but when screens get complex, your code can quickly become messy and hard to maintain. Beginners often struggle with organizing their views, especially when multiple UI components share the same data.


In this post, we’ll show you how to use a ViewModel to keep your SwiftUI views clean, simple, and scalable—no advanced skills required!


What’s Covered


  • SwiftUI ViewModel Basics: Learn how to encapsulate your view's state and data into a single class for improved organization and flexibility.

  • Refactoring Large SwiftUI Views: Discover how to break down complex screens into smaller, reusable components.

  • Practical Application: Follow a step-by-step example of creating and refactoring a screen for controlling an air conditioning unit.


What You’ll Learn


  • How to design and implement a ViewModel to simplify SwiftUI view development.

  • Techniques for improving code readability, maintainability, and scalability by breaking views into logical components.

  • How shared state in a ViewModel can reduce duplication and make views easier to manage.


Swiftly developing a first draft


Suppose we need to develop a screen for controlling an air conditioning (AC) unit like the one displayed below. In the top portion of the screen we have all the controls, and in the bottom half we simply reflect the current state.




In this screen we have the following functionality:

  • We can turn the unit on/off

  • We can toggle the AC between heating and cooling

  • We can set the temperature using a text field as well as a slider

  • We can toggle the fan on/off and set the speed.

  • At the bottom half of the screen we have images representing the current mode, fan speed, and a progress bar reflecting the current temperature progress to our desired temperature


When developing a SwiftUI screen like this, or any other screen for that matter, before I write any view code I like to start by defining the view model. It is a good idea to first determine what data the view represents. This screen happens to represent and control the AC’s power, mode, desired temperature, fan power, and fan speed. Using this information, here is the view model I implemented:

In this view model I have all the data and state information I will need in my view. What ever state and data is in this view model can be easily shared between different views by sharing this view model.


Here is the initial implementation of the view code I quickly developed using my view model, we will improve this later:


This view code accomplishes what we want, however this is not easily readable, maintainable, nor scalable. In its current state, the view code is very long (115 lines) and difficult to follow. Ideally we should be able to look at the code and easily locate the different sections of the screen and know what each one does. This makes it easier to maintain and to learn for new developers joining the team.


Using View Model to Clean SwiftUI Views


In order to improve our view code we should analyze our screen to see how we can break it apart into smaller logical components. We should be careful not to break down the screen just for the sake of creating smaller components, ideally a UI component is made of related UI elements that make sense to be put together.


After analyzing the screen for some time, I decided to group the UI elements into the following five groups displayed below.


SwiftUI View with View Model

The groups are as follows:

  1. This group controls the AC’s mode. We could move these into their own view component and call it AirConditionerModeControlsView.

  2. The two control views here adjust the desired temperature, so we could group them into a new view and call it AirConditionerTemperatureControlsView.

  3. These views control the fan, so let's group them into a new view called AirConditionerFanControlsView.

  4. The views in this group reflect the current operational status of the AC, so they could be grouped under AirConditionerOperationalStatusView.

  5. Lastly, these views belong together because they are used to display the temperature progress of the AC, so they could all go under a new component called AirConditionerProgressView.


Below you will see why it is a good idea to put as much state, especially shared state, in the view model, as opposed to using something like a @State property within each view.


Here we have the simplified AirConditionerView file. Notice that because each view uses the view model for its state, all I had to do is pass the view model along.


As you can see, the view code is broken down into the separate components I described earlier and is much easier to look at (only 24 lines of code). Breaking down the view like this makes it easier to see where each component on the screen is and where new components belong.


Following are the smaller view components. You will notice that I didn’t need to edit them much if at all:


AirConditionerModeControlsView

AirConditionerTemperatureControlsView

AirConditionerFanControlsView

AirConditionerOperationalStatusView


AirConditionerProgressView


Conclusion


By using a view model I was able to encapsulate all of my view's data and state in one class, which I could then share across different smaller views. By breaking my initial large view into smaller view components I made my code cleaner, more maintainable, and scalable. It also did not take much effort as all I had to do was pass the view model along. So next time you are developing a complex screen, remember what you learned here and give it a try!



Site
Join the growing community of iOS engineers who are taking their skills to the next level.

© 2025 Curious Algorithm. All rights reserved.

bottom of page