You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在macOS Widget中正确获取SwiftData数据?

解决macOS Widget中SwiftData数据为空的问题

核心问题

你当前的代码每次调用getItems()都会创建全新的ModelContainer,这个容器和主应用的SwiftData容器完全独立,自然读不到主应用存储的数据。

正确配置步骤

1. 共享SwiftData容器配置

主应用和Widget必须使用相同的ModelContainer配置,并指向同一个数据存储文件。先在主应用中定义全局共享的容器:

@main
struct MyMainApp: App {
    static let sharedModelContainer: ModelContainer = {
        let schema = Schema([Item.self])
        // 配置共享存储路径(需配合App Group)
        let containerURL = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: "group.com.yourcompany.yourapp")!
            .appendingPathComponent("AppData.sqlite")
        let modelConfig = ModelConfiguration(schema: schema, url: containerURL)
        
        do {
            return try ModelContainer(for: schema, configurations: [modelConfig])
        } catch {
            fatalError("初始化ModelContainer失败: \(error)")
        }
    }()

    var body: some Scene {
        WindowGroup {
            ContentView()
        }
        .modelContainer(MyMainApp.sharedModelContainer)
    }
}

2. 在Widget中复用共享容器

修改Widget的Provider,直接使用主应用的共享容器,不再创建新实例:

struct Provider: AppIntentTimelineProvider {
    // 复用主应用的共享容器
    private let modelContainer = MyMainApp.sharedModelContainer

    @MainActor func placeholder(in context: Context) -> SimpleEntry {
        SimpleEntry(date: Date(), configuration: ConfigurationAppIntent(), items: getItems())
    }

    func snapshot(for configuration: ConfigurationAppIntent, in context: Context) async -> SimpleEntry {
        await SimpleEntry(date: Date(), configuration: configuration, items: getItems())
    }
    
    func timeline(for configuration: ConfigurationAppIntent, in context: Context) async -> Timeline<SimpleEntry> {
        return Timeline(entries: [await SimpleEntry(date: Date(), configuration: configuration, items: getItems())], policy: .after(.now.advanced(by: 60 * 10)))
    }

    @MainActor func getItems() -> [Item] {
        let descriptor = FetchDescriptor<Item>()
        do {
            return try modelContainer.mainContext.fetch(descriptor)
        } catch {
            print("数据查询失败: \(error)")
            return []
        }
    }
}

3. 配置App Group实现跨目标共享

  • 在Xcode中分别选中主应用和Widget目标,进入Signing & Capabilities,添加App Groups能力,并创建/选择同一个分组(格式如group.com.yourcompany.yourapp)。
  • 确保Item模型文件同时添加到主应用和Widget的编译源中(或放在共享Framework里)。

额外注意事项

  • 不要用try?忽略错误,改用do-catch捕获并打印,方便排查问题。
  • Widget运行在后台,数据操作要尽量轻量,避免阻塞主线程。

内容的提问来源于stack exchange,提问作者Pytan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.08 01:57:16