Thuta Learning
ProjectsMobile Developmentintermediate

Project — Todo App (CRUD + SwiftData + MVVM)

Relax. We'll talk through this in plain words — no textbook voice.

What you'll walk away with

  • Understand Project — Todo App (CRUD + SwiftData + MVVM) with zero fear
  • Run the Xcode/SwiftUI code yourself
  • Apply this concept in a real project right away

Let's think about it this way for a second

A real app is split into layers — the View layer (SwiftUI screens), the ViewModel layer (business logic, ObservableObject), and the Data layer (SwiftData model). A Todo app needs to wire up all the CRUD operations (adding a new todo — Create, viewing the list — Read, toggling done/undone — Update, deleting an item — Delete) across all three layers.

Let's connect this to a real-world scenario

Build the three layers one at a time: `TodoItem` (@Model, data layer) → `TodoViewModel` (ObservableObject, with add/toggle/delete functions) → `TodoListScreen`/`AddTodoScreen` (View layer, List + NavigationStack). Use NavigationStack to connect the list screen to the add screen, and use `List`'s built-in swipe-to-delete for the delete operation.

Let's walk through it together

swift
struct TodoListScreen: View {
    @Query private var todos: [TodoItem]
    @Environment(\.modelContext) private var modelContext
    @State private var showingAddScreen = false

    var body: some View {
        NavigationStack {
            List {
                ForEach(todos) { todo in
                    HStack {
                        Image(systemName: todo.isDone ? "checkmark.circle.fill" : "circle")
                            .onTapGesture { todo.isDone.toggle() }
                        Text(todo.title)
                    }
                }
                .onDelete { indices in
                    for index in indices { modelContext.delete(todos[index]) }
                }
            }
            .navigationTitle("Todos")
            .toolbar {
                Button("Add") { showingAddScreen = true }
            }
        }
    }
}
You should see
Run the Todo app and you should be able to add todos, toggle done/undone, swipe to delete, and see your data still there after restarting the app.

5-minute try-it

Build the entire Todo app yourself with all three layers (Data/ViewModel/View) — verify that all four CRUD operations actually work on the Simulator.

A quick word of caution

If you delete a todo item permanently without offering an 'undo' option, that hurts the user experience — consider adding an alert dialog or an undo gesture instead.

Easy traps

  • Allowing swipe-to-delete to delete instantly without a confirmation dialog — an accidental swipe can wipe out a user's data
  • Leaving the empty state (when the todo list is blank) unhandled and showing just a blank screen — well-designed apps show a 'No todos yet' message instead

Now try it yourself

Build the entire Todo app yourself with all three layers (Data/ViewModel/View) — verify that all four CRUD operations actually work on the Simulator.

You'll know it worked when: Run the Todo app and you should be able to add todos, toggle done/undone, swipe to delete, and see your data still there after restarting the app.

Project — Todo App (CRUD + SwiftData + MVVM) | Thuta Learning