最近用 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 数据,我目前还不太清楚苹果的逻辑,不过应该是和小组件刷新限制有很大关系,后面再研究一下。