iOS 18 SwiftData ModelContext reset

Since the iOS 18 and Xcode 16, I've been getting some really strange SwiftData errors when passing @Model classes around.

The error I'm seeing is the following:

SwiftData/BackingData.swift:409: Fatal error: This model instance was destroyed by calling ModelContext.reset and is no longer usable. 

PersistentIdentifier(id: SwiftData.PersistentIdentifier.ID(url: x-coredata://34EE9059-A7B5-4484-96A0-D10786AC9FB0/TestApp/p2), implementation: SwiftData.PersistentIdentifierImplementation)

The same issue also happens when I try to retrieve a model from the ModelContext using its PersistentIdentifier and try to do anything with it. I have no idea what could be causing this.

I'm guessing this is just a bug in the iOS 18 Beta, since I couldn't find a single discussion about this on Google, I figured I'd mention it.

if someone has a workaround or something, that would be much appreciated.

Facing the same issue, does anyone know how to solve this issue?

Submitted Bug to Apple with ID: FB14089213

Anyone facing similar issue please reference this in your own report.

I got the exact same error message and resolved it by changing the way I create and keep my ModelContainer.

Cause:

Before, I created it in ContentView like this:

NavigationStackView()
    .modelContainer(MyModelContainer.create())

and accessed it in all other views via

@Environment(\.modelContext) private var modelContext

MyModelContainer.swift looked like this:

actor MyModelContainer
{
    @MainActor static func create() -> ModelContainer
    {
        let schema = Schema([MyModel.self])
        let configuration = ModelConfiguration("foo", url: FileManager.default.urls(for: .applicationSupportDirectory, in: .userDomainMask).first!.appendingPathComponent("foo.store"))
        let container = try ModelContainer(for: schema, configurations: [configuration])
        // ... fill it ...
        SomeSingleton.shared.modelContext = container.mainContext // Other classes need model access too
        return container
    }
}

I have 2 models, but I've ruled that out as a cause. I also ruled out that @Environment causes it, because the crash happened even if only my SomeSingleton accessed the modelContext.

Solution:

For me, the solution was to make container a member of MyModelContainer, which I turned into a Singleton:

@MainActor class MyModelContainer
{
    static let shared = MyModelContainer()
    let container: ModelContainer

    private init()
    {
        let schema = Schema([MyModel.self])
        let configuration = ModelConfiguration("foo", url: FileManager.default.urls(for: .applicationSupportDirectory, in: .userDomainMask).first!.appendingPathComponent("foo.store"))
        container = try ModelContainer(for: schema, configurations: [configuration])
        // ... fill it ...
    }
}

In other places (another Swift class, and SwiftUI), I access it via MyModelContainer.shared.container.mainContext. In SwiftUI, I removed all .modelContainer and @Environment lines. I suppose that these modifications might have also improved the thread safety and performance of my code, Apple probably had a reason for this change.

I'll also file a bug report as soon as I find the time to build a minimal example project.

Hope that helps 🙂

I filed FB14130653 with a minimal example project, and referenced the FB that @ashinthetray reported already.

Having thought about this some more, I retract my previous statement about my solution having improved the my code. I realized that now, without using @Environment, my code doesn't make use of SwiftData's simple model access in SwiftUI at all. This looks like a regression in the iOS 18 beta round (and visionOS 2, tvOS 18, macOS 15), and not like an intentional change.

NavigationStackView() .modelContainer(MyModelContainer.create()) this creates a new ModelContainer for the view, every time the view is created. Which probably isn't what you actually want. A singleton would be preferable. The view modifiers don't outlive the View instance, so this container should go away when the view does. It was a bug that it didn't on iOS 17.

The view instance in the tab controller in the sample should still be alive, however, and that is very weird. We're investigating.

The SwiftUI team strongly recommends moving the container creation into an @State variable:

@State var container = ModelContainer.create()

Facing the same issue.

Here is some code from my app for context:


In View

private func saveSocialPlatform() {
        guard !socialTitle.isEmpty else { return }
        
        let maxChars = Int(postTextMaxChars) ?? Int.max
        
        Task {
            let actor = SocialsModelActor(modelContainer: modelContext.container, mainActor: true)
            
            do {
                try await actor.saveSocial(socialTitle: socialTitle, hashtags: hashtags, maxCharsOption: maxChars, usesHashtags: usesHashtags, bestPractices: "")
                
                withAnimation {
                    show = false
                }
            } catch {
                print("Error saving a manual social platform: \(error.localizedDescription)")
            }
        }
    }

The ModelActor


actor SocialsModelActor: ModelActor {
    let modelContainer: ModelContainer
    let modelExecutor: any ModelExecutor
    
    init(modelContainer: ModelContainer) {
        let context = ModelContext(modelContainer)
        self.modelContainer = modelContainer
        modelExecutor = DefaultSerialModelExecutor(modelContext: context)
    }
    
    func saveSocial(
        socialTitle: String,
        hashtags: [String],
        maxCharsOption: Int,
        usesHashtags: Bool,
        bestPractices: String
    ) throws {
        let newHashtags = hashtags.map { Hashtag(title: $0) }
        try saveSocial(socialTitle: socialTitle, hashtags: newHashtags, maxCharsOption: maxCharsOption, usesHashtags: usesHashtags, bestPractices: bestPractices)
    }
    
    func saveSocial(
        socialTitle: String,
        hashtags: [Hashtag],
        maxCharsOption: Int,
        usesHashtags: Bool,
        bestPractices: String
    ) throws {
        try saveHashtags(hashtags: hashtags)
        
        let newSocial = SocialsPlatform(
            title: socialTitle,
            hashtags: hashtags,
            postTextMaxChars: maxCharsOption,
            usesHashtags: usesHashtags,
            bestPractices: bestPractices
        )
        
        modelContext.insert(newSocial)
        try modelContext.save()
    }
    
    func saveHashtags(
        hashtags: [Hashtag]
    ) throws {
        for hashtag in hashtags {
            modelContext.insert(hashtag)
        }
        try modelContext.save()
    }
    
    func saveHashtag(
        hashtag: Hashtag
    ) throws {
        modelContext.insert(hashtag)
        try modelContext.save()
    }
}

On top of the error discussed in the thread, using ModelActors will also trigger an old bug from over a year ago, where the UI won't refresh when an update was performed.

Has anyone found a solution yet?

iOS 18 SwiftData ModelContext reset
 
 
Q