SwiftUI ReferenceFileDocument class has data race problems

I recently added Swift compiler flags intended to catch concurrency warnings that will become errors in the future, adding -Xfrontend -warn-concurrency -enable-actor-data-race-checks to "Other Swift Flags" in my project build settings. These triggered both compile and runtime warnings about MainActor issues. The compile warns were about previews:

Static property '_previews' isolated to global actor 'MainActor' can not satisfy corresponding requirement from protocol '_PreviewProvider', and

Static property '_platform' isolated to global actor 'MainActor' can not satisfy corresponding requirement from protocol '_PreviewProvider'

But more troubling is the runtime console message:

warning: data race detected: @MainActor function at DataRace/DataRaceApp.swift:13 was not called on the main thread 2022-06-30 13:49:07.559517-0700 DataRace[2699:74516] warning: data race detected: @MainActor function at DataRace/DataRaceApp.swift:13 was not called on the main thread

The problem appears to be within the SwiftUI framework itself, and is easy to replicate:

  1. Create a macOS SwiftUI document based app, I named my example "DataRace"

  2. Add -Xfrontend -warn-concurrency -enable-actor-data-race-checks to "Other Swift Flags" in the project build settings

  3. Change the Document declaration, changing it from a FileDocument to a ReferenceFileDocument, replacing fileWrapper() with the snapshot()/fileWrapper() required by ReferenceFileDocument:

class DataRaceDocument: ReferenceFileDocument {
    var text: String

    init(text: String = "Hello, world!") {
        self.text = text
    }

    static var readableContentTypes: [UTType] { [.exampleText] }

    required init(configuration: ReadConfiguration) throws {
        guard let data = configuration.file.regularFileContents,
              let string = String(data: data, encoding: .utf8)
        else {
            throw CocoaError(.fileReadCorruptFile)
        }
        text = string
    }
    
    public func snapshot(contentType: UTType) throws -> Data {
        return text.data(using: .utf8)!
    }
    
    func fileWrapper(snapshot: Data, configuration: WriteConfiguration) throws -> FileWrapper {
        return .init(regularFileWithContents: snapshot)
    }
}
  1. Change the App DocumentGroup to the one appropriate for ReferenceFileDocument:
    var body: some Scene {
        DocumentGroup(newDocument: { DataRaceDocument() }) { file in
            ContentView(document: file.document)
        }
    }
}
  1. Lastly, change the ContentView to accommodate the previous changes:
    @ObservedObject var document: DataRaceDocument

    var body: some View {
        TextEditor(text: $document.text)
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView(document: DataRaceDocument())
    }
}

Compiling after these 4 changes will show the preview warnings. Run the app, save the default document, quit & restart the app and you will see the runtime warning.

The line that triggers it is in the DocumentGroup statement in the App:

DocumentGroup(newDocument: { DataRaceDocument() }) { file in
            ContentView(document: file.document)
        }

and breakpoints show it happening before DataRaceDocument.init() is called

Any ideas?

And yes, I did try @MainActor on the document class...It causes a whole slew of new warnings, and doesn't fix the data race.

SwiftUI ReferenceFileDocument class has data race problems
 
 
Q