NEW: Join my free 100 Days of SwiftUI challenge today! >>

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 NavigationView, 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.

To demonstrate this, 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 managed object 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 NavigationView stack, so we move back to the previous screen.

First, we need three new properties in our DetailView struct: one to hold our Core Data managed object context (so we can delete stuff), one to hold our presentation mode (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(\.managedObjectContext) var moc
@Environment(\.presentationMode) var presentationMode
@State private var showingDeleteAlert = false

The second step is writing a method that deletes the current book from our managed object 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 presentationMode.wrappedValue.dismiss() code.

Add this method to DetailView now:

func deleteBook() {
    moc.delete(book)

    // uncomment this line if you want to make the deletion permanent
    // try? self.moc.save()
    presentationMode.wrappedValue.dismiss()
}

The third step is to add an alert() modifier that watches showingDeleteAlert, along with an Alert view inside it asking 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.

SwiftUI gives us two specific button types for this purpose: .destructive takes a title and action closure and is shown in red to warn users it will destroy data, and .cancel() will just cause the alert to be dismissed. 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 GeometryReader in DetailView:

.alert(isPresented: $showingDeleteAlert) {
    Alert(title: Text("Delete book"), message: Text("Are you sure?"), primaryButton: .destructive(Text("Delete")) {
            self.deleteBook()
        }, secondaryButton: .cancel()
    )
}

The final step is to add a navigation bar item that starts the deletion process – this just need to flip the showingDeleteAlert Boolean, because our alert() modifier is already watching it. So, add this one last modifier to the GeometryReader in DetailView:

.navigationBarItems(trailing: Button(action: {
    self.showingDeleteAlert = true
}) {
    Image(systemName: "trash")
})

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!

LEARN SWIFTUI FOR FREE I have a massive, free SwiftUI video collection on YouTube teaching you how to build complete apps with SwiftUI – check it out!

BUY OUR BOOKS
Buy Pro Swift 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 (Vapor Edition) 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 Server-Side Swift (Kitura Edition) Buy Beyond Code

Was this page useful? Let us know!

Average rating: 5.0/5