SwiftData with SwiftUI and MVVM

WWDC2023

Ashish Langhe
3 min readNov 15, 2023

In the dynamic realm of iOS development, the synergy between SwiftData, SwiftUI, and the Model-View-ViewModel (MVVM) architectural pattern stands out as a powerful combination. This guide will take you through an in-depth exploration of SwiftData’s integration with SwiftUI within the MVVM paradigm, showcasing a complete example that demonstrates the seamless flow of data between models, views, and view models.

Introduction to MVVM

MVVM is an architectural pattern that promotes a clear separation of concerns within an application. It comprises three main components:

1. Model: Represents the data and business logic of the application.
2. View: Displays the user interface and reacts to user input.
3. ViewModel: Acts as an intermediary between the model and view, handling data presentation and user interactions.

SwiftData Model

Let’s begin by defining a simple data model using SwiftData. For this example, we’ll create a `Task` struct to represent tasks in a to-do list:

swift
struct Task {
var id: UUID
var title: String
var completed: Bool
}

ViewModel Implementation

Next, we’ll create a `TaskViewModel` class that conforms to the MVVM pattern. This class will be responsible for managing the tasks and interacting with the SwiftUI views:

swift
import SwiftData


class TaskViewModel: ObservableObject {
@Published var tasks: [Task] = []
init() {
// Initialize tasks or fetch them from a data source
// For simplicity, we'll add a sample task
tasks.append(Task(id: UUID(), title: "Sample Task", completed: false))
}
}

In a real-world scenario, you would fetch tasks from a server or a local database within the `init` method.

SwiftData Integration

Now, let’s enhance the `TaskViewModel` to include SwiftData functionality for tasks management. We’ll use SwiftData to fetch and update tasks:

swift
import SwiftData

class TaskViewModel: ObservableObject {
@Published var tasks: [Task] = []
init() {
// Initialize tasks or fetch them from a data source using SwiftData
// For simplicity, we'll add a sample task
tasks.append(Task(id: UUID(), title: "Sample Task", completed: false))
}
func fetchTasks() {
// Use SwiftData to fetch tasks from a data source
// Update the tasks array when data is retrieved
}
func updateTask(_ task: Task) {
// Use SwiftData to update the task in the data source
// Trigger UI refresh through @Published property
}
}

SwiftUI View

With the ViewModel in place, let’s create a SwiftUI view that displays the list of tasks. We’ll use `TaskListView`:

swift
import SwiftUI

struct TaskListView: View {
@ObservedObject var viewModel: TaskViewModel
var body: some View {
List(viewModel.tasks) { task in
TaskRowView(task: task)
}
}
}

TaskRowView Implementation

To enhance the presentation of each task in the list, we’ll create a separate `TaskRowView`:

swift
import SwiftUI

struct TaskRowView: View {
var task: Task
var body: some View {
HStack {
Text(task.title)
Spacer()
Image(systemName: task.completed ? "checkmark.circle.fill" : "circle")
}
.padding()
}
}

Fetching and Updating Data in SwiftUI View

Finally, let’s integrate data fetching and updating operations directly within a SwiftUI view using the `onAppear` and `onTapGesture` modifiers:

swift
import SwiftUI

struct TaskListView: View {
@ObservedObject var viewModel: TaskViewModel
var body: some View {
List(viewModel.tasks) { task in
TaskRowView(task: task)
}
.onAppear {
viewModel.fetchTasks()
}
.onTapGesture {
// Simulate task completion toggle
if let firstTask = viewModel.tasks.first {
var updatedTask = firstTask
updatedTask.completed.toggle()
viewModel.updateTask(updatedTask)
}
}
}
}

In this example, the tasks are fetched when the view appears (`onAppear`), and tapping on the list item simulates updating the task completion status.

Conclusion

SwiftData, when harmoniously integrated with SwiftUI and MVVM, provides a robust framework for developing scalable and maintainable iOS applications. The example presented here demonstrates the flow of data from the model to the view through the view model, showcasing the power and flexibility of this architecture. Feel free to expand upon this example by adding more features, such as task creation and deletion, to further explore the capabilities of SwiftData in SwiftUI within an MVVM architecture.

Happy coding!

--

--

Ashish Langhe

I'm Ashish Langhe, a Senior Software Engineer with over 7+ years of expertise in developing native and cross-platform mobile applications.