modelContext.save triggers warning: publishing changes from background threads is not allowed

I am seeing a strange warning pop up in my SwiftData ModelActor:

Publishing changes from background threads is not allowed; make sure to publish values from the main thread (via operators like receive(on:)) on model updates.

This warning is triggered by the try self.modelContext.save() call in the following function in my ModelActor:

    public func purgeLocalEvents(for calendarId: PersistentIdentifier) async {
        do {
            let calendars = try self.modelContext.fetch(CalendarFetchDescriptors.getCalendar(calendarId))
            if let calendar = calendars.first {
                if let events = calendar.events {
                    for event in events {
                        self.modelContext.delete(event)
                    }
                }

                calendar.lastSync = .distantPast
                try self.modelContext.save()
            }
        } catch {
            debugPrint("Error loading calendar for event purge", error.localizedDescription)
        }
    }

The function in the ModelActor is called like this:

        Task.detached(priority: .userInitiated) {
            let actor = await RemoteGoogleCalendarActor(modelContainer: SwiftDataCoordinator.shared.fullContainer)
            await actor.purgeLocalEvents(for: calendarId)
        }

I perform saves from modelactors in many other places, and I've never seen this warning before. What could be causing this issue?

Answered by DTS Engineer in 808620022

The waring message says what it means: You probably updated a published property from a background queue.

modelContext.save triggers notifications such as ModelContext.didSave or .NSManagedObjectContextDidSave from the queue where the save method is called.

In your case, it seems that you use the model context provided by ModelActor, and so the notifications will be triggered from a background queue. If you happen to observe the notifications and change a published property from within the notification handler, you will get the warning.

You can fix that kind of warning by running the code that updates the published property from the main queue (using MainActor).

Best,
——
Ziqiao Chen
 Worldwide Developer Relations.

Accepted Answer

The waring message says what it means: You probably updated a published property from a background queue.

modelContext.save triggers notifications such as ModelContext.didSave or .NSManagedObjectContextDidSave from the queue where the save method is called.

In your case, it seems that you use the model context provided by ModelActor, and so the notifications will be triggered from a background queue. If you happen to observe the notifications and change a published property from within the notification handler, you will get the warning.

You can fix that kind of warning by running the code that updates the published property from the main queue (using MainActor).

Best,
——
Ziqiao Chen
 Worldwide Developer Relations.

Thanks!

Elsewhere in my code I am observing a didSave notification:

.onReceive(NotificationCenter.default.publisher(for: ModelContext.didSave)) { object in
...

So this call is triggering that warning, and it is telling me that whoever is observing didSave will not get notifications from that specific call, since it is running on a background thread.

I think I get it :)

modelContext.save triggers warning: publishing changes from background threads is not allowed
 
 
Q