【Xcode/Swift】Building a SwiftUI App with MVVM: Fetching Data from an API

In modern app development, fetching data from an API is a common requirement. One popular architectural pattern for building robust and maintainable apps is MVVM (Model-View-ViewModel). In this blog post, we will explore how to fetch data from an API using SwiftUI and MVVM architecture.

Setting up the Project

To get started, create a new SwiftUI project in Xcode. We will build a simple app that fetches a list of posts from the JSONPlaceholder API and displays them in a list view.

The Model

Let’s begin by defining our data model. In this case, we have a Post struct with id, title, and body properties. Add the following code to your project:

struct Post: Codable {
    let id: Int
    let title: String
    let body: String

    init(id: Int, title: String, body: String) {
        self.id = id
        self.title = title
        self.body = body
    }
}

The ViewModel

Next, we need to create a ViewModel that will handle fetching the data from the API and storing it. Create a new Swift file called PostViewModel and add the following code:

import SwiftUI

class PostViewModel: ObservableObject {
    @Published var posts: [Post] = []

    func fetchPosts() {
        guard let url = URL(string: "https://jsonplaceholder.typicode.com/posts") else {
            return
        }

        let task = URLSession.shared.dataTask(with: url) { data, _, error in
            guard let data = data else {
                return
            }

            do {
                let decoder = JSONDecoder()
                let decodedPosts = try decoder.decode([Post].self, from: data)

                DispatchQueue.main.async {
                    self.posts = decodedPosts
                }
            } catch {
                print("Error decoding posts: \(error)")
            }
        }
        task.resume()
    }
}

The PostViewModel class contains a @Published property posts that will automatically update any associated views when its value changes. The fetchPosts() method uses URLSession to make a network request to the API and decode the response into an array of Post objects.

The View

Now let’s create the view that will display the fetched data. Replace the contents of the ContentView with the following code:

struct PostView: View {
    @ObservedObject var viewModel = PostViewModel()

    var body: some View {
        NavigationView {
            List(viewModel.posts, id: \.id) { post in
                VStack(alignment: .leading) {
                    Text(post.title)
                        .font(.headline)
                    Text(post.body)
                        .font(.subheadline)
                        .foregroundColor(.gray)
                }
            }
            .navigationBarTitle("Posts")
        }
        .onAppear {
            viewModel.fetchPosts()
        }
    }
}

struct PostView_Previews: PreviewProvider {
    static var previews: some View {
        PostView()
    }
}

In this code, we create a HomeView that initializes an instance of PostViewModel and observes its posts property using @ObservedObject. Inside the view, we display the fetched posts in a list. The navigationBarTitle sets the title of the navigation bar to “Posts”. Finally, in the onAppear modifier, we call the fetchPosts() method to fetch the data when the view appears.

Testing the App

Build and run the app in the simulator or on a device. You should see a list of posts fetched from the API displayed in the app’s view. The data will be populated as soon as it is retrieved from the API.

Conclusion

In this blog post, we explored how to fetch data from an API using SwiftUI and MVVM architecture. We created a PostViewModel to handle the network request and store the fetched data, and a HomeView to display the data in a list view. By following the MVVM pattern, we achieved separation of concerns and a clear structure for our app. Feel free to expand upon this example by adding more features or customizations to suit your needs.