UPGRADE YOUR SKILLS: Learn advanced Swift and SwiftUI on Hacking with Swift+! >>

Using an alert to pop a NavigationLink programmatically

Paul Hudson    @twostraws   

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!

Hacking with Swift is sponsored by RevenueCat

SPONSORED Take the pain out of configuring and testing your paywalls. RevenueCat's Paywalls allow you to remotely configure your entire paywall view without any code changes or app updates.

Learn more here

Sponsor Hacking with Swift and reach the world's largest Swift community!

BUY OUR BOOKS
Buy Pro Swift Buy Pro SwiftUI Buy Swift Design Patterns Buy Testing Swift Buy Hacking with iOS Buy Swift Coding Challenges Buy Swift on Sundays Volume One Buy Server-Side Swift Buy Advanced iOS Volume One Buy Advanced iOS Volume Two Buy Advanced iOS Volume Three Buy Hacking with watchOS Buy Hacking with tvOS Buy Hacking with macOS Buy Dive Into SpriteKit Buy Swift in Sixty Seconds Buy Objective-C for Swift Developers Buy Beyond Code

Was this page useful? Let us know!

Average rating: 4.8/5

 
Unknown user

You are not logged in

Log in or create account
 

Link copied to your pasteboard.