Deleting a Realm object in a SwiftUI List with cascading delete

106 Views Asked by At

I've been reading through the Realm SwiftUI tutorial doc at https://www.mongodb.com/docs/realm/sdk/swift/swiftui-tutorial/ and studying their sample code. That code (specifically the version that does not use Atlas device sync) shows an example of deleting a row in a SwiftUI list by calling onDelete(perform:). This is great for deleting the underlying Realm object that corresponds to the row but if that object has a property that represents a "to-many" relationship (i.e., a List), those objects obviously don't get deleted since Realm doesn't perform "chaining" or "cascading" deletes for you. Here's a simple example implementation based on the sample code in the Realm tutorial:

class WidgetContainer: Object, ObjectKeyIdentifiable {

    @Persisted(primaryKey: true) var _id: ObjectId
    @Persisted var widgets = List<Widget>()
}

class Widget: Object, ObjectKeyIdentifiable {

    @Persisted(primaryKey: true) var _id: ObjectId
    @Persisted var name: String = ""
}

And here's the view code:

struct WidgetContainerView: View {

    @ObservedResults(WidgetContainer.self) var widgetContainers
    
    var body: some View {
        List {
            ForEach(widgetContainers) { container in
                WidgetContainerDetailView(container: container)
            }
            .onDelete(perform: $widgetContainers.remove)
        }
    }
}

That onDelete(perform:) will obviously delete the backing WidgetContainer object but not any Widget objects that might be in the container's .widgets list property. I've been reading through the Realm docs to understand how to implement this myself and I think I've managed to get it working but I'm wondering if there is a better/easier way to do this. Here's the method that I currently have implemented:

struct WidgetContainerView: View {

    @ObservedResults(WidgetContainer.self) var widgetContainers
    
    var body: some View {
        List {
            ForEach(widgetContainers) { container in
                WidgetContainerDetailView(container: container)
            }
            .onDelete(perform: delete(at:))
        }
    }
    
    private func delete(at offsets: IndexSet) {
        for i in offsets {
            if let widgetContainer = $widgetContainers.wrappedValue[i].thaw() {
                try? widgetContainer.realm?.write {
                    widgetContainer.realm?.delete(widgetContainer.widgets)
                }
            }
            $widgetContainers.remove(atOffsets: offsets)
        }
    }
}

Any suggestions or thoughts on ways to improve this or potential problems I should be aware of? Thanks very much!

0

There are 0 best solutions below