最近用 SwfitUI 开发了一款新应用 — 时光周期,为了赶潮流,用到了最新的桌面小组件特性(还未上线该功能)。但在开发的过程中因为对新特新的不了解还是遇到了不少的坑,尤其是 CoreData 数据的获取上。

和宿主App中使用 CoreData 不一样的是,我们无法在小组件中的 View 中直接获取 CoreData 数据。

struct  ExampleEntryView: View {
    ///////////////// 这个在宿主 App 中是可以正常使用的,但在 widget 则无法使用
    @FetchRequest(
        sortDescriptors: [NSSortDescriptor(keyPath: \Item.timestamp, ascending: true)],
        animation: .default)
    private var items: FetchedResults<Item>
    /////////////////
    var body: some View {
    // some codes...
    }
}

那么如果需要正常获取数据,该怎么办呢?

答案就是在 timeline provider 中进行数据获取

struct Provider: IntentTimelineProvider {
    var managedObjectContext : NSManagedObjectContext
    
    init(context : NSManagedObjectContext) {
        self.managedObjectContext = context
    }

    // 自定义函数,获取 item 的数量
    private func getDataCount() -> Int {
        let request = NSFetchRequest<Item>(entityName: "Item")
        
        do {
            let allItems = try managedObjectContext.fetch(request)
            return allItems.count
        } catch  {
            
        }
        return 0
    }
    // 在这些函数内调用 getDataCount 即可获取想要的数据
    func placeholder(....) {
        
    }
    func getSnapshot(....) {
        ....
        // 这里即将getDataCount() 的值传递给 SimpleEntry 的 itemCount
        let mySimpleEntry = SimpleEntry(data: Date(), configuration: configuration, itemCount: getDataCount())
        ....
    } 

    func getTimeline(....) {

    }
}

然后在你的 timeline entry 中设置 itemCount 属性

struct SimpleEntry: TimelineEntry {
    let date: Date
    let configuration: ConfigurationIntent
    let itemCount: Int
}

最后,在 Widget View 中就能获取到 itemCount 这个属性的值了

struct  ExampleEntryView: View {
    var entry: Provider.Entry
    var body: some View {
        // some codes...
        Text("\(entry.itemCount)")
    }
}

至于小组件为什么无法在 View 中直接获取 CoreData 数据,我目前还不太清楚苹果的逻辑,不过应该是和小组件刷新限制有很大关系,后面再研究一下。

Categorized in:

Tagged in:

,