在小部件中获取 CoreData
Fetch CoreData in a Widget
我正在尝试从我的核心数据中获取实体和属性以显示在小部件中,但确实很困难。目前我可以获取实体的 ItemCount,但这不是我要显示的内容。我希望能够显示我保存在 Core Data 中的字符串和图像。我查看了大量网站,包括 ,但没有成功。
我当前的设置有一个用于核心数据的工作应用程序组,该应用程序组共享给主应用程序和小部件。
这是用于显示实体的 ItemCount 的 Widget.swift 代码:
import WidgetKit
import SwiftUI
import CoreData
private struct Provider: TimelineProvider {
func placeholder(in context: Context) -> SimpleEntry {
SimpleEntry(date: Date())
}
func getSnapshot(in context: Context, completion: @escaping (SimpleEntry) -> Void) {
let entry = SimpleEntry(date: Date())
completion(entry)
}
func getTimeline(in context: Context, completion: @escaping (Timeline<Entry>) -> Void) {
let midnight = Calendar.current.startOfDay(for: Date())
let nextMidnight = Calendar.current.date(byAdding: .day, value: 1, to: midnight)!
let entries = [SimpleEntry(date: midnight)]
let timeline = Timeline(entries: entries, policy: .after(nextMidnight))
completion(timeline)
}
}
private struct SimpleEntry: TimelineEntry {
let date: Date
}
private struct MyAppWidgetEntryView: View {
var entry: Provider.Entry
let moc = PersistenceController.shared.container.viewContext
let predicate = NSPredicate(format: "favorite == true")
let request = NSFetchRequest<Project>(entityName: "Project")
var body: some View {
// let result = try moc.fetch(request)
VStack {
Image("icon")
.resizable()
.aspectRatio(contentMode: .fit)
Text("Item Count: \(itemsCount)")
.padding(.bottom)
.foregroundColor(.secondary)
}
}
var itemsCount: Int {
let request = NSFetchRequest<NSFetchRequestResult>(entityName: "Project")
do {
return try PersistenceController.shared.container.viewContext.count(for: request)
} catch {
print(error.localizedDescription)
return 0
}
}
}
@main
struct MyAppWidget: Widget {
let kind: String = "MyAppWidget"
var body: some WidgetConfiguration {
StaticConfiguration(kind: kind, provider: Provider()) { entry in
MyAppWidgetEntryView(entry: entry)
}
.configurationDisplayName("MyApp Widget")
.description("Track your project count")
.supportedFamilies([.systemSmall])
}
}
但是,我真正希望能够做的是从实体访问属性 bodyText
或 image1
,就像我的主应用程序访问它的方式一样。例如,
VStack {
Image(uiImage: UIImage(data: project.image1 ?? self.projectImage1)!)
.resizable()
.aspectRatio(contentMode: .fill)
Text("\(project.bodyText!)")
}
这是 Widget.swift 代码,它似乎更接近我要完成的目标,但它无法获得 project.bodyText
并出现错误 Value of type 'FetchedResults<Project>' has no member 'bodyText'
-- 我想不通为什么它没有看到我的实体 Project
的属性
// MARK: Core Data
var managedObjectContext: NSManagedObjectContext {
return persistentContainer.viewContext
}
var workingContext: NSManagedObjectContext {
let context = NSManagedObjectContext(concurrencyType: .privateQueueConcurrencyType)
context.parent = managedObjectContext
return context
}
var persistentContainer: NSPersistentCloudKitContainer = {
let container = NSPersistentCloudKitContainer(name: "MyAppApp")
let storeURL = URL.storeURL(for: "group.com.me.MyAppapp", databaseName: "MyAppApp")
let description = NSPersistentStoreDescription(url: storeURL)
container.loadPersistentStores(completionHandler: { storeDescription, error in
if let error = error as NSError? {
print(error)
}
})
container.viewContext.automaticallyMergesChangesFromParent = true
container.viewContext.mergePolicy = NSMergeByPropertyStoreTrumpMergePolicy
return container
}()
// MARK: WIDGET
struct Provider: TimelineProvider {
// CORE DATA
var moc = managedObjectContext
init(context : NSManagedObjectContext) {
self.moc = context
}
// WIDGET
func placeholder(in context: Context) -> SimpleEntry {
SimpleEntry(date: Date())
}
func getSnapshot(in context: Context, completion: @escaping (SimpleEntry) -> ()) {
let entry = SimpleEntry(date: Date())
completion(entry)
}
func getTimeline(in context: Context, completion: @escaping (Timeline<Entry>) -> ()) {
var entries: [SimpleEntry] = []
// Generate a timeline consisting of five entries an hour apart, starting from the current date.
let currentDate = Date()
for hourOffset in 0 ..< 5 {
let entryDate = Calendar.current.date(byAdding: .hour, value: hourOffset, to: currentDate)!
let entry = SimpleEntry(date: entryDate)
entries.append(entry)
}
let timeline = Timeline(entries: entries, policy: .atEnd)
completion(timeline)
}
}
struct SimpleEntry: TimelineEntry {
let date: Date
}
struct MyAppWidgetEntryView : View {
var entry: Provider.Entry
@FetchRequest(entity: Project.entity(), sortDescriptors: []) var project: FetchedResults<Project>
var body: some View {
Text("\(project.bodyText)"). <--------------------- ERROR HAPPENS HERE
}
}
@main
struct MyAppWidget: Widget {
let kind: String = "MyAppWidget"
var body: some WidgetConfiguration {
StaticConfiguration(kind: kind, provider: Provider(context: managedObjectContext)) { entry in
MyAppWidgetEntryView(entry: entry)
.environment(\.managedObjectContext, managedObjectContext)
}
.configurationDisplayName("My Widget")
.description("This is an example widget.")
}
}
struct MyAppWidget_Previews: PreviewProvider {
static var previews: some View {
MyAppWidgetEntryView(entry: SimpleEntry(date: Date()))
.previewContext(WidgetPreviewContext(family: .systemSmall))
}
}
我接近了吗?你有没有碰巧得到类似的工作?非常感谢!
您可以删除这些行
let storeURL = URL.storeURL(for: "group.com.me.MyAppapp", databaseName: "MyAppApp")
let description = NSPersistentStoreDescription(url: storeURL)
而是像这样覆盖 defaultDirectoryURL():
override public class func defaultDirectoryURL() -> URL {
let storeURL = FileManager.default.containerURL(
forSecurityApplicationGroupIdentifier: "group.com.me.MyAppapp"
)
return storeURL!
}
编辑:
刚刚看到您没有 NSPersistentCloudKitContainer 的子类,您应该有一个可以覆盖 defaultDirectoryURL() 并提供持久存储的默认位置的子类。
此外,拥有一个 single/shared NSPersistentCloudKitContainer 实例也是一个好习惯,这样您就不会在每次使用 NSPersistentCloudKitContainer 变量时都加载商店。
据我在互联网上的了解,@NSFetchRequest 在 Widgets 中不起作用。
我为小部件创建了一个 CoreDataManager class,它将从“getTimeline”获取数据
我的代码有点复杂,因为我的小部件是可配置的,但也许它可以帮助您了解如何让它工作。
首先是在主应用程序和小部件之间共享的 DataController。
class DataController: ObservableObject {
let container: NSPersistentCloudKitContainer
init(inMemory: Bool = false) {
container = NSPersistentCloudKitContainer(name: "Main", managedObjectModel: Self.model)
let storeURL = URL.storeURL(for: "MyGroup", databaseName: "Main")
let storeDescription = NSPersistentStoreDescription(url: storeURL)
storeDescription.cloudKitContainerOptions = NSPersistentCloudKitContainerOptions(
containerIdentifier: "Identifier"
)
container.persistentStoreDescriptions = [storeDescription]
guard let description = container.persistentStoreDescriptions.first else {
Log.shared.add(.coreData, .error, "###\(#function): Failed to retrieve a persistent store description.")
fatalError("###\(#function): Failed to retrieve a persistent store description.")
}
description.setOption(true as NSNumber, forKey: NSPersistentHistoryTrackingKey)
description.setOption(true as NSNumber, forKey: NSPersistentStoreRemoteChangeNotificationPostOptionKey)
if inMemory {
container.persistentStoreDescriptions.first?.url = URL(fileURLWithPath: "/dev/null")
}
container.loadPersistentStores { (_, error) in
if let error = error {
Log.shared.add(.cloudKit, .fault, "Fatal error loading store \(error)")
fatalError("Fatal error loading store \(error.localizedDescription)")
}
}
container.viewContext.automaticallyMergesChangesFromParent = true
container.viewContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy
}
static let model: NSManagedObjectModel = {
guard let url = Bundle.main.url(forResource: "Main", withExtension: "momd") else {
fatalError("Failed to locate model file.")
}
guard let managedObjectModel = NSManagedObjectModel(contentsOf: url) else {
fatalError("Failed to load model file.")
}
return managedObjectModel
}()
}
Widget 的 CoreDataManager
class CoreDataManager {
var vehicleArray = [Vehicle]()
let dataController: DataController
private var observers = [NSObjectProtocol]()
init(_ dataController: DataController) {
self.dataController = dataController
fetchVehicles()
/// Add Observer to observe CoreData changes and reload data
observers.append(
NotificationCenter.default.addObserver(forName: .NSPersistentStoreRemoteChange, object: nil, queue: .main) { _ in //swiftlint:disable:this line_length discarded_notification_center_observer
self.fetchVehicles()
}
)
}
deinit {
/// Remove Observer when CoreDataManager is de-initialized
observers.forEach(NotificationCenter.default.removeObserver)
}
/// Fetches all Vehicles from CoreData
func fetchVehicles() {
defer {
WidgetCenter.shared.reloadAllTimelines()
}
dataController.container.viewContext.refreshAllObjects()
let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "Vehicle")
do {
guard let vehicleArray = try dataController.container.viewContext.fetch(fetchRequest) as? [Vehicle] else {
return
}
self.vehicleArray = vehicleArray
} catch {
print("Failed to fetch: \(error)")
}
}
}
我确实将我的 CoreData 模型“车辆”添加到 WidgetEntry
struct WidgetEntry: TimelineEntry {
let date: Date
let configuration: SelectedVehicleIntent
var vehicle: Vehicle?
}
Timeline Provider 在重新加载时间线时获取所有 CoreData 并将我的核心数据模型注入 WidgetEntry
struct Provider: IntentTimelineProvider {
/// Access to CoreDataManger
let dataController = DataController()
let coreDataManager: CoreDataManager
init() {
coreDataManager = CoreDataManager(dataController)
}
/// Placeholder for Widget
func placeholder(in context: Context) -> WidgetEntry {
WidgetEntry(date: Date(), configuration: SelectedVehicleIntent(), vehicle: Vehicle.example)
}
/// Provides a timeline entry representing the current time and state of a widget.
func getSnapshot(for configuration: SelectedVehicleIntent, in context: Context, completion: @escaping (WidgetEntry) -> Void) { //swiftlint:disable:this line_length
vehicleForWidget(for: configuration) { selectedVehicle in
let entry = WidgetEntry(
date: Date(),
configuration: configuration,
vehicle: selectedVehicle
)
completion(entry)
}
}
/// Provides an array of timeline entries for the current time and, optionally, any future times to update a widget.
func getTimeline(for configuration: SelectedVehicleIntent, in context: Context, completion: @escaping (Timeline<WidgetEntry>) -> Void) { //swiftlint:disable:this line_length
coreDataManager.fetchVehicles()
/// Fetches the vehicle selected in the configuration
vehicleForWidget(for: configuration) { selectedVehicle in
let currentDate = Date()
var entries: [WidgetEntry] = []
// Create a date that's 60 minutes in the future.
let nextUpdateDate = Calendar.current.date(byAdding: .minute, value: 60, to: currentDate)!
// Generate an Entry
let entry = WidgetEntry(date: currentDate, configuration: configuration, vehicle: selectedVehicle)
entries.append(entry)
let timeline = Timeline(entries: entries, policy: .after(nextUpdateDate))
completion(timeline)
}
}
/// Fetches the Vehicle defined in the Configuration
/// - Parameters:
/// - configuration: Intent Configuration
/// - completion: completion handler returning the selected Vehicle
func vehicleForWidget(for configuration: SelectedVehicleIntent, completion: @escaping (Vehicle?) -> Void) {
var selectedVehicle: Vehicle?
defer {
completion(selectedVehicle)
}
for vehicle in coreDataManager.vehicleArray where vehicle.uuid?.uuidString == configuration.favoriteVehicle?.identifier { //swiftlint:disable:this line_length
selectedVehicle = vehicle
}
}
}
最后是 WidgetView
struct WidgetView: View {
var entry: Provider.Entry
var body: some View {
VStack {
Text("CoreData: \(entry.vehicle?.fuel?.count ?? 99999)")
Text("Name: \(entry.vehicle?.brand ?? "No Vehicle found")")
Divider()
Text("Refreshed: \(entry.date, style: .relative)")
.font(.caption)
}
.padding(.all)
}
}
确保在文件检查器的目标成员列表中选中核心数据模型。
我正在尝试从我的核心数据中获取实体和属性以显示在小部件中,但确实很困难。目前我可以获取实体的 ItemCount,但这不是我要显示的内容。我希望能够显示我保存在 Core Data 中的字符串和图像。我查看了大量网站,包括
我当前的设置有一个用于核心数据的工作应用程序组,该应用程序组共享给主应用程序和小部件。
这是用于显示实体的 ItemCount 的 Widget.swift 代码:
import WidgetKit
import SwiftUI
import CoreData
private struct Provider: TimelineProvider {
func placeholder(in context: Context) -> SimpleEntry {
SimpleEntry(date: Date())
}
func getSnapshot(in context: Context, completion: @escaping (SimpleEntry) -> Void) {
let entry = SimpleEntry(date: Date())
completion(entry)
}
func getTimeline(in context: Context, completion: @escaping (Timeline<Entry>) -> Void) {
let midnight = Calendar.current.startOfDay(for: Date())
let nextMidnight = Calendar.current.date(byAdding: .day, value: 1, to: midnight)!
let entries = [SimpleEntry(date: midnight)]
let timeline = Timeline(entries: entries, policy: .after(nextMidnight))
completion(timeline)
}
}
private struct SimpleEntry: TimelineEntry {
let date: Date
}
private struct MyAppWidgetEntryView: View {
var entry: Provider.Entry
let moc = PersistenceController.shared.container.viewContext
let predicate = NSPredicate(format: "favorite == true")
let request = NSFetchRequest<Project>(entityName: "Project")
var body: some View {
// let result = try moc.fetch(request)
VStack {
Image("icon")
.resizable()
.aspectRatio(contentMode: .fit)
Text("Item Count: \(itemsCount)")
.padding(.bottom)
.foregroundColor(.secondary)
}
}
var itemsCount: Int {
let request = NSFetchRequest<NSFetchRequestResult>(entityName: "Project")
do {
return try PersistenceController.shared.container.viewContext.count(for: request)
} catch {
print(error.localizedDescription)
return 0
}
}
}
@main
struct MyAppWidget: Widget {
let kind: String = "MyAppWidget"
var body: some WidgetConfiguration {
StaticConfiguration(kind: kind, provider: Provider()) { entry in
MyAppWidgetEntryView(entry: entry)
}
.configurationDisplayName("MyApp Widget")
.description("Track your project count")
.supportedFamilies([.systemSmall])
}
}
但是,我真正希望能够做的是从实体访问属性 bodyText
或 image1
,就像我的主应用程序访问它的方式一样。例如,
VStack {
Image(uiImage: UIImage(data: project.image1 ?? self.projectImage1)!)
.resizable()
.aspectRatio(contentMode: .fill)
Text("\(project.bodyText!)")
}
这是 Widget.swift 代码,它似乎更接近我要完成的目标,但它无法获得 project.bodyText
并出现错误 Value of type 'FetchedResults<Project>' has no member 'bodyText'
-- 我想不通为什么它没有看到我的实体 Project
// MARK: Core Data
var managedObjectContext: NSManagedObjectContext {
return persistentContainer.viewContext
}
var workingContext: NSManagedObjectContext {
let context = NSManagedObjectContext(concurrencyType: .privateQueueConcurrencyType)
context.parent = managedObjectContext
return context
}
var persistentContainer: NSPersistentCloudKitContainer = {
let container = NSPersistentCloudKitContainer(name: "MyAppApp")
let storeURL = URL.storeURL(for: "group.com.me.MyAppapp", databaseName: "MyAppApp")
let description = NSPersistentStoreDescription(url: storeURL)
container.loadPersistentStores(completionHandler: { storeDescription, error in
if let error = error as NSError? {
print(error)
}
})
container.viewContext.automaticallyMergesChangesFromParent = true
container.viewContext.mergePolicy = NSMergeByPropertyStoreTrumpMergePolicy
return container
}()
// MARK: WIDGET
struct Provider: TimelineProvider {
// CORE DATA
var moc = managedObjectContext
init(context : NSManagedObjectContext) {
self.moc = context
}
// WIDGET
func placeholder(in context: Context) -> SimpleEntry {
SimpleEntry(date: Date())
}
func getSnapshot(in context: Context, completion: @escaping (SimpleEntry) -> ()) {
let entry = SimpleEntry(date: Date())
completion(entry)
}
func getTimeline(in context: Context, completion: @escaping (Timeline<Entry>) -> ()) {
var entries: [SimpleEntry] = []
// Generate a timeline consisting of five entries an hour apart, starting from the current date.
let currentDate = Date()
for hourOffset in 0 ..< 5 {
let entryDate = Calendar.current.date(byAdding: .hour, value: hourOffset, to: currentDate)!
let entry = SimpleEntry(date: entryDate)
entries.append(entry)
}
let timeline = Timeline(entries: entries, policy: .atEnd)
completion(timeline)
}
}
struct SimpleEntry: TimelineEntry {
let date: Date
}
struct MyAppWidgetEntryView : View {
var entry: Provider.Entry
@FetchRequest(entity: Project.entity(), sortDescriptors: []) var project: FetchedResults<Project>
var body: some View {
Text("\(project.bodyText)"). <--------------------- ERROR HAPPENS HERE
}
}
@main
struct MyAppWidget: Widget {
let kind: String = "MyAppWidget"
var body: some WidgetConfiguration {
StaticConfiguration(kind: kind, provider: Provider(context: managedObjectContext)) { entry in
MyAppWidgetEntryView(entry: entry)
.environment(\.managedObjectContext, managedObjectContext)
}
.configurationDisplayName("My Widget")
.description("This is an example widget.")
}
}
struct MyAppWidget_Previews: PreviewProvider {
static var previews: some View {
MyAppWidgetEntryView(entry: SimpleEntry(date: Date()))
.previewContext(WidgetPreviewContext(family: .systemSmall))
}
}
我接近了吗?你有没有碰巧得到类似的工作?非常感谢!
您可以删除这些行
let storeURL = URL.storeURL(for: "group.com.me.MyAppapp", databaseName: "MyAppApp")
let description = NSPersistentStoreDescription(url: storeURL)
而是像这样覆盖 defaultDirectoryURL():
override public class func defaultDirectoryURL() -> URL {
let storeURL = FileManager.default.containerURL(
forSecurityApplicationGroupIdentifier: "group.com.me.MyAppapp"
)
return storeURL!
}
编辑:
刚刚看到您没有 NSPersistentCloudKitContainer 的子类,您应该有一个可以覆盖 defaultDirectoryURL() 并提供持久存储的默认位置的子类。
此外,拥有一个 single/shared NSPersistentCloudKitContainer 实例也是一个好习惯,这样您就不会在每次使用 NSPersistentCloudKitContainer 变量时都加载商店。
据我在互联网上的了解,@NSFetchRequest 在 Widgets 中不起作用。
我为小部件创建了一个 CoreDataManager class,它将从“getTimeline”获取数据
我的代码有点复杂,因为我的小部件是可配置的,但也许它可以帮助您了解如何让它工作。
首先是在主应用程序和小部件之间共享的 DataController。
class DataController: ObservableObject {
let container: NSPersistentCloudKitContainer
init(inMemory: Bool = false) {
container = NSPersistentCloudKitContainer(name: "Main", managedObjectModel: Self.model)
let storeURL = URL.storeURL(for: "MyGroup", databaseName: "Main")
let storeDescription = NSPersistentStoreDescription(url: storeURL)
storeDescription.cloudKitContainerOptions = NSPersistentCloudKitContainerOptions(
containerIdentifier: "Identifier"
)
container.persistentStoreDescriptions = [storeDescription]
guard let description = container.persistentStoreDescriptions.first else {
Log.shared.add(.coreData, .error, "###\(#function): Failed to retrieve a persistent store description.")
fatalError("###\(#function): Failed to retrieve a persistent store description.")
}
description.setOption(true as NSNumber, forKey: NSPersistentHistoryTrackingKey)
description.setOption(true as NSNumber, forKey: NSPersistentStoreRemoteChangeNotificationPostOptionKey)
if inMemory {
container.persistentStoreDescriptions.first?.url = URL(fileURLWithPath: "/dev/null")
}
container.loadPersistentStores { (_, error) in
if let error = error {
Log.shared.add(.cloudKit, .fault, "Fatal error loading store \(error)")
fatalError("Fatal error loading store \(error.localizedDescription)")
}
}
container.viewContext.automaticallyMergesChangesFromParent = true
container.viewContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy
}
static let model: NSManagedObjectModel = {
guard let url = Bundle.main.url(forResource: "Main", withExtension: "momd") else {
fatalError("Failed to locate model file.")
}
guard let managedObjectModel = NSManagedObjectModel(contentsOf: url) else {
fatalError("Failed to load model file.")
}
return managedObjectModel
}()
}
Widget 的 CoreDataManager
class CoreDataManager {
var vehicleArray = [Vehicle]()
let dataController: DataController
private var observers = [NSObjectProtocol]()
init(_ dataController: DataController) {
self.dataController = dataController
fetchVehicles()
/// Add Observer to observe CoreData changes and reload data
observers.append(
NotificationCenter.default.addObserver(forName: .NSPersistentStoreRemoteChange, object: nil, queue: .main) { _ in //swiftlint:disable:this line_length discarded_notification_center_observer
self.fetchVehicles()
}
)
}
deinit {
/// Remove Observer when CoreDataManager is de-initialized
observers.forEach(NotificationCenter.default.removeObserver)
}
/// Fetches all Vehicles from CoreData
func fetchVehicles() {
defer {
WidgetCenter.shared.reloadAllTimelines()
}
dataController.container.viewContext.refreshAllObjects()
let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "Vehicle")
do {
guard let vehicleArray = try dataController.container.viewContext.fetch(fetchRequest) as? [Vehicle] else {
return
}
self.vehicleArray = vehicleArray
} catch {
print("Failed to fetch: \(error)")
}
}
}
我确实将我的 CoreData 模型“车辆”添加到 WidgetEntry
struct WidgetEntry: TimelineEntry {
let date: Date
let configuration: SelectedVehicleIntent
var vehicle: Vehicle?
}
Timeline Provider 在重新加载时间线时获取所有 CoreData 并将我的核心数据模型注入 WidgetEntry
struct Provider: IntentTimelineProvider {
/// Access to CoreDataManger
let dataController = DataController()
let coreDataManager: CoreDataManager
init() {
coreDataManager = CoreDataManager(dataController)
}
/// Placeholder for Widget
func placeholder(in context: Context) -> WidgetEntry {
WidgetEntry(date: Date(), configuration: SelectedVehicleIntent(), vehicle: Vehicle.example)
}
/// Provides a timeline entry representing the current time and state of a widget.
func getSnapshot(for configuration: SelectedVehicleIntent, in context: Context, completion: @escaping (WidgetEntry) -> Void) { //swiftlint:disable:this line_length
vehicleForWidget(for: configuration) { selectedVehicle in
let entry = WidgetEntry(
date: Date(),
configuration: configuration,
vehicle: selectedVehicle
)
completion(entry)
}
}
/// Provides an array of timeline entries for the current time and, optionally, any future times to update a widget.
func getTimeline(for configuration: SelectedVehicleIntent, in context: Context, completion: @escaping (Timeline<WidgetEntry>) -> Void) { //swiftlint:disable:this line_length
coreDataManager.fetchVehicles()
/// Fetches the vehicle selected in the configuration
vehicleForWidget(for: configuration) { selectedVehicle in
let currentDate = Date()
var entries: [WidgetEntry] = []
// Create a date that's 60 minutes in the future.
let nextUpdateDate = Calendar.current.date(byAdding: .minute, value: 60, to: currentDate)!
// Generate an Entry
let entry = WidgetEntry(date: currentDate, configuration: configuration, vehicle: selectedVehicle)
entries.append(entry)
let timeline = Timeline(entries: entries, policy: .after(nextUpdateDate))
completion(timeline)
}
}
/// Fetches the Vehicle defined in the Configuration
/// - Parameters:
/// - configuration: Intent Configuration
/// - completion: completion handler returning the selected Vehicle
func vehicleForWidget(for configuration: SelectedVehicleIntent, completion: @escaping (Vehicle?) -> Void) {
var selectedVehicle: Vehicle?
defer {
completion(selectedVehicle)
}
for vehicle in coreDataManager.vehicleArray where vehicle.uuid?.uuidString == configuration.favoriteVehicle?.identifier { //swiftlint:disable:this line_length
selectedVehicle = vehicle
}
}
}
最后是 WidgetView
struct WidgetView: View {
var entry: Provider.Entry
var body: some View {
VStack {
Text("CoreData: \(entry.vehicle?.fuel?.count ?? 99999)")
Text("Name: \(entry.vehicle?.brand ?? "No Vehicle found")")
Divider()
Text("Refreshed: \(entry.date, style: .relative)")
.font(.caption)
}
.padding(.all)
}
}
确保在文件检查器的目标成员列表中选中核心数据模型。