Enabling undo with multi-model schema

.modelContainer(for: MyMode.self, isUndoEnabled: true)

This may work for single model containers, but I have a number of models. I don't see how to enable undo for multiple model containers.

Replies

(Don't post while sleepy)

Right in the docs... .modelContainer(for: [MyModel1.self, MyModel2.self], isUndoEnabled: true)

Trying to figure out if this is possible for a sharedModelContainer. When creating a new empty multiplatform app with SwiftData, this code is automatically generated in the App.swift:

import SwiftUI
import SwiftData

@main
struct SwiftDataTestApp: App {
    var sharedModelContainer: ModelContainer = {
        let schema = Schema([
            Item.self,
        ])
        let modelConfiguration = ModelConfiguration(schema: schema, isStoredInMemoryOnly: false)

        do {
            return try ModelContainer(for: schema, configurations: [modelConfiguration])
        } catch {
            fatalError("Could not create ModelContainer: \(error)")
        }
    }()

    var body: some Scene {
        WindowGroup {
            ContentView()
        }
        .modelContainer(sharedModelContainer)
    }
}

Is there a way to set isUndoEnabled in this scenario? Doesn't look like ModelContainer(for: Schema...) supports it?

  • A hackingwithswift article suggests creating a new UndoManager for the shared container. However, this technique doesn't work for me and Undo/Redo commands are greyed out in my test app.

    container = try ModelContainer(for: Store.self, Book.self)
    container.mainContext.undoManager = UndoManager()
    
  • Unlike the Hacking with Swift article, I set my undo manager from the environment and it works. The only catch you can't do in the app context, it has to be on a view level. In any content view, we can access undo manager through the @Environment(\.undoManager) var undoManager, then when I create my content view I initiate the background task using the .task modifier, and setting the under manager: modelContext.undoManager = undoManager. It's probably not a best practice though.

  • as Borisy did I managed to have it working with by getting the undo manager from the environment on the ContentView

    @Environment(\.modelContext) private var modelContext
    @Environment(\.undoManager) private var undoManager
    

    Then I use the onAppear modifier

        .onAppear() {
            modelContext.undoManager = undoManager
        }
    

    Then it works as expected.

Add a Comment

do { let container = try ModelContainer(for: schema, configurations: [modelConfiguration]) container.mainContext.undoManager = UndoManager() return container
} catch { fatalError("Could not create ModelContainer: (error)") }

do {
 let container = try ModelContainer(for: schema, configurations: [modelConfiguration]) 
 container.mainContext.undoManager = UndoManager() 
 return container
} catch { fatalError("Could not create ModelContainer: (error)") }

when you need to undo

@Environment(\.modelContext) var modelContext

modelContext.undoManager?.undo()