You’ve already seen how NavigationLink
lets us push to a detail screen, which might be a custom view or one of SwiftUI’s built-in types such as Text
or Image
. Because we’re inside a NavigationStack
, iOS automatically provides a “Back” button to let users get back to the previous screen, and they can also swipe from the left edge to go back. However, sometimes it’s useful to programmatically go back – i.e., to move back to the previous screen when we want rather than when the user swipes.
We've looked at this before, so hopefully this is just good practice for you: we’re going to add one last feature to our app that deletes whatever book the user is currently looking at. To do this we need to show an alert asking the user if they really want to delete the book, then delete the book from the current model context if that’s what they want. Once that’s done, there’s no point staying on the current screen because its associated book doesn’t exist any more, so we’re going to pop the current view – remove it from the top of the NavigationStack
stack, so we move back to the previous screen.
First, we need three new properties in our DetailView
struct: one to hold our SwiftData model context (so we can delete stuff), one to hold our dismiss action (so we can pop the view off the navigation stack), and one to control whether we’re showing the delete confirmation alert or not.
So, start by adding these three new properties to DetailView
:
@Environment(\.modelContext) var modelContext
@Environment(\.dismiss) var dismiss
@State private var showingDeleteAlert = false
The second step is writing a method that deletes the current book from our model context, and dismisses the current view. It doesn’t matter that this view is being shown using a navigation link rather than a sheet – we still use the same dismiss()
code.
Add this method to DetailView
now:
func deleteBook() {
modelContext.delete(book)
dismiss()
}
The third step is to add an alert()
modifier that watches showingDeleteAlert
, and asks the user to confirm the action. So far we’ve been using simple alerts with a dismiss button, but here we need two buttons: one button to delete the book, and another to cancel. Both of these have specific button roles that automatically make them look correct, so we’ll use those.
Apple provides very clear guidance on how we should label alert text, but it comes down to this: if it’s a simple “I understand” acceptance then “OK” is good, but if you want users to make a choice then you should avoid titles like “Yes” and “No” and instead use verbs such as “Ignore”, “Reply”, and “Confirm”.
In this instance, we’re going to use “Delete” for the destructive button, then provide a cancel button next to it so users can back out of deleting if they want. So, add this modifier to the ScrollView
in DetailView
:
.alert("Delete book", isPresented: $showingDeleteAlert) {
Button("Delete", role: .destructive, action: deleteBook)
Button("Cancel", role: .cancel) { }
} message: {
Text("Are you sure?")
}
The final step is to add a toolbar item that starts the deletion process – this just needs to flip the showingDeleteAlert
Boolean, because our alert()
modifier is already watching it. So, add this one last modifier to the ScrollView
:
.toolbar {
Button("Delete this book", systemImage: "trash") {
showingDeleteAlert = true
}
}
You can now delete books in ContentView
using swipe to delete or the edit button, or navigate into DetailView
then tap the dedicated delete button in there – it should delete the book, update the list in ContentView
, then automatically dismiss the detail view.
That’s another app complete – good job!
SAVE 50% All our books and bundles are half price for Black Friday, so you can take your Swift knowledge further without spending big! Get the Swift Power Pack to build your iOS career faster, get the Swift Platform Pack to builds apps for macOS, watchOS, and beyond, or get the Swift Plus Pack to learn advanced design patterns, testing skills, and more.
Link copied to your pasteboard.