Thanks for being a part of WWDC25!

How did we do? We’d love to know your thoughts on this year’s conference. Take the survey here

ModelContext.model(for:) returns deleted objects

I'm writing some tests to confirm the behavior of my app. White creating a model actor to delete objects I realized that ModelContext.model(for:) does return objects that are deleted. I was able to reproduces this with this minimal test case:

@Model class Activity {
    init() {}
}

struct MyLibraryTests {
    let modelContainer = try! ModelContainer(
        for: Activity.self,
        configurations: ModelConfiguration(
            isStoredInMemoryOnly: true
        )
    )

    init() throws {
        let context = ModelContext(modelContainer)

        context.insert(Activity())
        try context.save()
    }

    @Test func modelForIdAfterDelete() async throws {
        let context = ModelContext(modelContainer)
        let id = try context.fetch(FetchDescriptor<Activity>()).first!.id

        context.delete(context.model(for: id) as! Activity)
        try context.save()

        let result = context.model(for: id) as? Activity
        #expect(result == nil) // Expectation failed: (result → MyLibrary.Activity) == nil
    }

    @Test func fetchDescriptorAfterDelete() async throws {
        let context = ModelContext(modelContainer)
        let id = try context.fetch(FetchDescriptor<Activity>()).first!.id

        context.delete(context.model(for: id) as! Activity)
        try context.save()

        let result = try context.fetch(
            FetchDescriptor<Activity>(predicate: #Predicate { $0.id == id })
        ).first

        #expect(result == nil)
    }
}

Here I create a new context, insert an model and save it. The test modelForIdAfterDelete does fail, as result still contains the deleted object. I also tried to check #expect(result!.isDeleted), but it is also false.

With the second test I use a FetchDescriptor to retrieve the object by ID and it correctly returns nil.

Shouldn't both methods use a consistent behavior?

I'm writing some tests to confirm the behavior of my app, you are actually unit testing SwiftData and not your app.

As for the problem, I am not sure it's a bug and that they deliberately keep the object in the ModelContext for a short while to avoid problems for the app using it.

The following test would pass though

#expect(result.isDeleted)

Thanks for your answer. I've tried this before, but it does not work either:

let result = context.model(for: id) as? Activity
#expect(result?.isDeleted == true)
// Expectation failed: (result?.isDeleted → false) == true
ModelContext.model(for:) returns deleted objects
 
 
Q