How can I share SwiftData @Model between widget and app?

I have an App Group shared between my app and its widgets.

I have SwiftData's @Model, updated from the widget intent's perform() method and displayed on the app and the widget.

@MainActor
func perform() async throws -> some IntentResult {
    let context = try ModelContainer(for: MyModel.self).mainContext
    let myModel = try ModelContainer(for: MyModel.self).mainContext.fetch(
        FetchDescriptor<MyModel>(predicate: #Predicate {
            // The predicate is not the problem.
        })
    ).first

    myModel?.functionThatModifiesMyModel()

    return .result()
}

Both the app and the widget SwiftUI views access to the model using Macros.

@Environment(\.modelContext) var context
@Query(sort: \.whatever) var myModel: [MyModel]
But the data is never correct in the app code (the widget's data is updated correctly using the intent).

Why doesn't the model make it to the app?

Replies

I have the same issue. The app is working fine with SwiftData and updates the widget when changes made. I am though not using App Groups but iCloud to share data.

When the app is open (in the background) and the Widget intent is updating the data, the widget is working fine but the app is not updating. After completely closing the app and opening back up the data is updated.

When the app is fully closed and the Widget intent updating the data, opening the app is showing the correct data.

After completely closing the app and opening back up the data is updated.

I also experience this issue

did you ever find a solution to this problem? I am experiencing the same.

Containers are references. The correct way to achieve this I think would be by using AppDependencyManager. Here is a working example:

@Model
final class Test: @unchecked Sendable {
    var text: String
    
    init(text: String) {
        self.text = text
    }
}

struct InsertTestIntent: AppIntent {
    static var title: LocalizedStringResource = "Insert model"
    
    static var openAppWhenRun: Bool = true
    static var isDiscoverable: Bool = false
    
    @Parameter(title: "Text")
    var text: String

    @Dependency
    private var modelContainer: ModelContainer
    
    init(text: String) {
        self.text = text
    }
    
    init() {}
    
    @MainActor
    func perform() async throws -> some IntentResult {
        modelContainer.mainContext.insert(Test(text: text))
        return .result()
    }
}

struct ContentView: View {

    @Query
    private var items: [Test]
    
    @State
    private var text = ""
    
    var body: some View {
        NavigationStack {
            List {
                TextField("Text", text: $text)
                Button("Insert model", intent: InsertTestIntent(text: text))
                Section {
                    ForEach(items) { item in
                        Text(item.text)
                    }
                }
            }
            .navigationTitle("Home")
        }
    }
}