SwiftData ModelContext.didSave not firing for deletion events

1 day ago 1
ARTICLE AD BOX

The basis for this is that I have an app where I am modifying a database using a simple Model: Record.

If I insert 10 records, and perform modelContext.save() I receive the notification (ModelContext.didSave) after I perform the save.

If I delete records, tand perform modelContext.save() there is no notification at all.

If I insert 10 records, and perform modelContext.save() I receive the notification (ModelContext.didSave) after I perform the save. However, the notification I receive after the save only shows the 10 (new) inserted records, and 0 deleted records.

Sample code:

extension ModelContext { static func subscribeForNotifications( printChanges: Bool = false, block: @Sendable @escaping (NotificationCenter.Notifications.Iterator.Element) -> Void ) -> Task<Void, Never> { let center = NotificationCenter.default let notificationName = ModelContext.didSave return Task.detached(priority: .userInitiated) { for await notification in center.notifications(named: notificationName) { block(notification) } } } } func insert10(modelContext: ModelContext) { Task.detached(priority: .userInitiated) { (1...10).forEach { let record = Record(id: UUID(), title: "Record \($0)") context.insert(record) } try! context.save() } } // One at a time func removeAllRecords(context: ModelContext) { let descriptor = FetchDescriptor<Record>() Task.detached(priority: .userInitiated { try context.fetch(descriptor) .forEach { context.delete($0) } } try context.save() } } // More effecient func removeEfficiently(context: ModelContext) { try context.delete(model: Record.self) try context.save() } func subscribeForNotifications() { notificationTask = ModelContext .subscribeForNotifications(printChanges: true) { _ in print("Received notification") Task { @MainActor in await self.reload() } } }

Note: This code was extracted from a larger project. Threading is not a concern here, as everything is actually done through @ModelActor but showing all those redirections is confusing.

The issue is that when I call these functions in the order presented:

subscribeForNotifications() insert10(context: modelContext) removeAllRecords(context: modelContext) insert10(context: modelContext) removeEfficiently(context: modelContext)

I only receive a notification after the inserts and not after the deletes. If I restart the program, the database is empty, as expected. I never receive any notifications that have the Notification.deletedIdentifiers having any values in the array.

Question: Why don't I get a notification when I delete records?

NOTE: I know I can work-around this by calling self.reload() in the two remove()functions, but I was hoping the notification system would alert me as to when I need to reload. I prefer using the MVVM model where my ViewModel handles the fetches, inserts, deletes, etc. rather than using @Query macro in the actual View.

Also: using @Query in my code rather than a more MVVM style will show the changes on every save, so there must be a mechanism within SwiftData to notice when the underlying DB is modified.

Read Entire Article