MVVM in SwiftUI

MVVM in SwiftUI

A tutorial on making a Post view with Model-View-ViewModel Design Pattern

·

4 min read

Model-View-ViewModel (MVVM) is an architectural pattern that has gained a lot of popularity in recent years, especially in the context of developing mobile applications. With the release of SwiftUI, Apple's new framework for building user interfaces, MVVM has become even more relevant. In this blog, we'll take a closer look at how MVVM can be implemented in SwiftUI with a sample list of posts.

The code in this post is available here.

What the heck is MVVM

First, let's take a brief look at the three components of MVVM:

  1. Model: This represents the data and how the data get structured. In most cases, a model is a struct or multiple structs.

  2. View: This represents the user interface of the application. It includes things like buttons, labels, text fields, and other UI elements, and of course, a representation of the data in the front end.

  3. ViewModel: This acts as a mediator between the View and the Model. It exposes data from the Model to the View and handles user interactions from the View to the Model. Basically, it handles the business logic, such as preparing data, sorting, event handling.

Implementation

Let’s create a simple List-of-Posts app to taste MVVM.

First of all, we need to build up the model.

    struct Post {
        let id: Int
        let title: String
        let description: String
    }

In the example above, we created a struct called Post with three properties. And later we’re going to display the content of Post items. Here Post is our model since it defines what data we are going to process.

Second, we build the view model to prepare the post data for the view.

    class PostViewModel: ObservableObject {
        @Published var posts: [Post] = []
        func getPosts() {
            posts = [
                .init(id: 1, title: "Lorem ipsum dolor sit amet", description: "consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam"),
                .init(id: 2, title: "quis nostrud exercitation", description: "ullamco laboris nisi ut aliquip ex ea commodo consequat"),
                .init(id: 3, title: "Duis aute irure dolor in reprehenderit", description: "in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.")
            ]
        }
    }

In this example, we have a class called PostViewModel that has a posts property and a function called getPosts that is responsible for loading the posts from an API. (For demo purpose, I’m initializing some values manually.) The @Published property wrapper is used to make the posts property observable, which allows the View to update itself whenever the property changes.

And finally, it comes to the view. In SwiftUI, Views are typically created using declarative syntax. This means that we define the UI elements and their properties using a hierarchy of views. Here's an example of a view that displays a list of posts:

    struct ContentView: View {
        @StateObject var vm = PostViewModel()
        var body: some View {
            NavigationView {
                List {
                    ForEach(vm.posts, id: \.id) { post in
                        HStack {
                            VStack(alignment: .leading) {
                                Text(post.title).bold()
                                Text(post.description)
                                    .lineLimit(2)
                                    .font(.footnote)
                                    .foregroundColor(.secondary)
                            }
                            Spacer()
                            Text("\(post.id)")
                                .bold()
                                .foregroundColor(.secondary)
                                .padding()
                        }
                    }
                }
                .navigationTitle("Posts - MVVM")
            }
            .onAppear {
                vm.getPosts()
            }
        }
    }

In this example, we have a view called ContentView displaying a list of posts. The view has a reference to a PostViewModel, which is responsible for loading the posts and providing them to the view. The List element is used to display the posts in a scrollable list, and each post has a row with its title, description and ID. The onAppear modifier calls the getPosts function inside the view model so that all three posts will get ready when the view loads.

Now that all MVVM components are done, we can check the preview canvas and you can see that all three posts are shown. Our code is simply and clean, we only have to call the getPosts function in the view and the view itself only defines what the UI should look like, without touching the business logic (getPosts function in our case).

In summary, MVVM is a powerful architectural pattern that can be used to build scalable and maintainable applications. With SwiftUI, it is easier than ever to implement MVVM in your projects. The sample list of posts shown here demonstrates how MVVM can be used to build a simple, yet functional, application.

And that’s all of today’s post. I hope it helps and let me know if it is by leaving a comment. Don’t forget to subscribe to my newsletter if you’d like to receive posts like this via email.

I’ll see you in the next post!