SwiftData and discarding unsaved changes

Continuing my standard weekend project of just playing with things, and I have a little inventory app. Basically something like

@Model
final class Room {
    var id: UUID
    var name: String
    @Relationship(deleteRule: .cascade, inverse: \Item.room) var items: [Item]
}

@Model
final class Item {
    var id: UUID
    var name: String
    @Relationship(deleteRule: .nullify) room: Room
}

Then in a SwiftUI view for each Room, I use another ItemsView that constructs a query predicate based on the room ID that is passed in. And then on that, I've got a sheet to edit it, which is passed in @Bindable var item: Item, and has a form to edit it, and cancel & save buttons. Standard stuff.

But if I edit the fields in the Item, they get reflected immediately, which, ok, that's actually what I wanted so yay. But the "Save" button calls context.save() while the "Cancel" button doesn't -- it calls context.rollback() (and I have auto-save off).

And the problem I've got is: when I do that, the ItemsView updates, in real time, but when I cancel, it doesn't update; I have to quit and relaunch the app to get that properly in sync.

The easiest change I can make, I presume, is to simply not use the passed in Item, but simply copy its values around to a new instance, but that won't update the item, so I'd have to delete it and re-insert it, or copy the fields back in the completion handler, or any number of things.

So my question really is: assuming what I just described makes sense, what's the proper way to deal with it?

I found a work around for your small project, I would place a @State string on the TableView or ListView and place an onChangeModifier on the selectedItem to update the string. Then I would @Bindable that String to the Sheet and compare both string once cancel in call. If they are different I would save the old version. This is a quick and dirty way about solving this issue right now. For larger applications I would recommend doing this. Yes, it has to be on the Collection View for how SwiftUI redraws the views all the time.

Also I don't know if you know this but if you call save after doing a rollback and not restarting the application it will take what ever is in the SwiftUI View and save that back to the database. So, always restart your application before calling modelContext.save().

In the CoreData days we would just reset the Context and Fetch a new list of item from CoreData. Without having to restart the application, you could make CoreData Model and that stack to call that one function but I don't really think it I worth it.

People with larger apps, I would pretty much make a secondary struct to hold that information in until this bug gets fixed. It is a big one. I even tried some of my old tricks that I used to use with CoreData to get the UI to update, and none of them have work with this framework.

In practice, I was using completion to do the context.save() so I can deal with workarounds. But it... seems to totally defeat the purpose of @Bindable and requiring a context.save() if you can't get back to an earlier state.

SwiftData and discarding unsaved changes
 
 
Q