Enabling undo CoreData + SwiftUI

I did a post a while back about how to enable undo functionality when using CoreData. It continues to work great for AppKit or UIKit apps, but what about if you’ve adopted SwiftUI as Apple is suggesting we do?

BestWaySwiftUI

Well… unfortunately the previous approach won’t work quite as well.

After a few hours working this, it turns out it’s quite simple… You have two options:

1. Using the @Environment property:

First, be sure you pass the right managedObjectContext to your top level view as part of the @main App:

    var body: some Scene {

        WindowGroup {

            someTopLevelView

                .environment(\.managedObjectContext,container.viewContext)

        }

Then, in the SwiftUI file where you want to add undo functionality you’ll add the  following @Environment properties

//CoreData convinience

    @Environment(\.managedObjectContext) private var viewContext

    @Environment(\.undoManager) private var undoManager

And then you’ll connect them, ensuring the SwiftUI undoManager is connected to the one you’ve created:

    someView

    .onAppear{

        viewContext.undoManager = undoManager

     }

Voila!

2. Alternatively you can implement your own Undo/Redo Commands in SwiftUI:

    .commands {

        CommandGroup(replacing: .undoRedo) {

            Button(“Undo”) {

                //Trigger  your own undo with your created undoManager

                undoManager?.undo()

            }

            .keyboardShortcut(KeyEquivalent(“z”), modifiers: [.command])

            .disabled(undoManager?.canUndo == false)

            Button(“Redo”) {

                //Trigger  your own undo with your created undoManager

                undoManager?.redo()

            }

            .keyboardShortcut(KeyEquivalent(“z”), modifiers: [.command, .shift])

            .disabled(undoManager?.canRedo == false)

        }

    }

 

And that’s it, now you have full undo functionality for Core Data in SwiftUI. 

Questions / comments? I’m at @MarcMasVi 

Marc