SwiftData document-based app broken

Hello all

Synopsis: document based SwiftData app breaks document handling after first save due to internal error saving the -shm file.

Long: i am working on a small document based SwiftData app for macOS. The UI works well as long as the document was not saved. After saving the document and reopening it, I get an error consistently in console:

BUG IN CLIENT OF libsqlite3.dylib: database integrity compromised by API violation: vnode unlinked while in use: /Users/vrunkel/Library/Containers/de.ecoobs.CurtailmentAnalyzer/Data/tmp/TemporaryItems/NSIRD_CurtailmentAnalyzer_mrXKMs/NewDocument/StoreContent-shm

So somehow the -shm file is still referenced to NewDocument created when the app opens an untitled document and resides in the temporary folder. I have saved the document to my documents folder.

After reopening and the above error deletion or addition of items crashes the app with a long backtrace to view updating:

Modifications to the layout engine must not be performed from a background thread after it has been accessed from the main thread.

I am not creating any threads or do background work. If I do not save the document but work within the new untitled document no problems occur. Even closing the app and reopening the untitled new doc (happens automatically) all is fine.

To rule out any influence of my existing view structure I have created the most simple test case - Xcode -> New Project -> macOS document based app configured to use SwiftData.

Same behaviour. After saving a new document the addition/deletion of items causes the thread-induced crash and shows the error in console when opening the document.

I am using latest versions of Xcode 15.0 and macOS 14.0

Any ideas?

thx, volker

Has anyone gotten SwiftData to work with SwiftUI's DocumentGroup? Even the (unmodified) Xcode Multiplatform document app template using SwiftData crashes when working with a saved document. I suspect that the DocumentGroup extension for SwiftData is not creating the context on the main thread, but only when re-opening saved documents. On macOS it crashes with the above mentioned error, but I have also seen this manifest as threading deadlocks (on the iPad and macOS).

With the all the work that was apparently put into SwiftData I'm incredulous that this would just flat out not work. I am hoping I am missing something, but (based on the unpopularity of UIManagedDocument) I fear that most people are simply not working with SwiftData in document-based apps or not using it with DocumentGroup (e.g. using it alongside Core Data).

I am hoping there is a work-around, as I have already invested a lot of time converting from Core Data.

In case anyone wants to dig further into this issue, I was able to demonstrate that the underlying NSManagedObjectContext is being created with "main queue concurrency" for new documents, but "private queue concurrency" when re-opening a document (I am guessing this is the issue).

I added the following debug code to my main view (which has @Environment(\.modelContext) private var modelContext declared):

.onAppear(perform: {
    if let moc = Mirror(reflecting: _modelContext.wrappedValue).descendant("_nsContext") as? NSManagedObjectContext {
        switch moc.concurrencyType {
        case .confinementConcurrencyType:
            print("Confinement Concurrency")
        case .privateQueueConcurrencyType:
            print("Private Queue Concurrency")
        case .mainQueueConcurrencyType:
            print("Main Queue Concurrency")
        }
        moc.perform {
            print("Context is on main thread??? -> \(Thread.current.isMainThread)")
        }
    }
})

[@Volker Runkel](https://developer.apple.com/forums/profile/Volker Runkel) - This isn't something I would recommend going to production with, and I doubt it's a complete solution (I am still seeing SQLite errors in the debug console), but in order to continue development I have come up with the following work-around (at least until I hear back from DTS):

@main
struct TestDocumentAppApp: App {
    var body: some Scene {
        DocumentGroup(editing: .itemDocument, migrationPlan: TestDocumentAppMigrationPlan.self) {
            IntermediarySceneView {
                ContentView()
            }
        }
    }
}

struct IntermediarySceneView<Content: View>: View {
    @Environment(\.modelContext) private var originalModelContext
    let content: Content

    var body: some View {
        content.environment(\.modelContext, originalModelContext.container.mainContext)
    }

    init(@ViewBuilder content: () -> Content) {
        self.content = content()
    }
}

Basically, all this is doing is overriding the modelContext variable by traversing back to the container and grabbing the mainContext (AFAIK that is what it should be). It seems to prevent crashes in my limited testing, but there is a good chance there are issues elsewhere (I'm not sure where else the incorrect context may still be in use), so YMMV.

FYI - I have been instructed by DTS to file a bug report for this issue. If anyone else is experiencing crashes or freezes when trying to implement a document-based app using SwiftData, please file a bug report so we can get the issue prioritized! If DTS are able to provide a work-around, I will post it here.

Response from DTS:

We believe this issue is a bug. Please file a bug report via Feedback Assistant (https://feedbackassistant.apple.com). For more information on Feedback Assistant, visit https://developer.apple.com/bug-reporting.

FWIW I filed one already. The more the merrier.

Updated macOS to 14.1 and Xcode to 15.0.1. Built my app and opened one of the existing documents that lead to above crash. Adding and deleting item now worked. Created a new document. All worked well after reopening. Seems the update fixed it for me. Can anyone confirm?

thx volker

SwiftData document-based app broken
 
 
Q