Как отображать данные из Core Data в WidgetKit

Вот мой код, и я попытался перечислить сохраненные данные из Core Data в WidgetKit, которые вообще не отображаются. Я уже создал группу приложений, и данные отображаются при предварительном просмотре, но когда мы добавляем виджет на главный экран, ничего не отображается. Я не уверен, что поступил правильно или нет.

Как лучше всего вывести список записей Core Data в WidgetKit?

import WidgetKit
import SwiftUI
import CoreData

// MARK: For Core Data

public extension URL {
    /// Returns a URL for the given app group and database pointing to the sqlite database.
    static func storeURL(for appGroup: String, databaseName: String) -> URL {
        guard let fileContainer = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: appGroup) else {
            fatalError("Shared file container could not be created.")
        }

        return fileContainer.appendingPathComponent("\(databaseName).sqlite")
    }
}

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: "Countdowns")

    let storeURL = URL.storeURL(for: "group.app-group-countdowns", databaseName: "Countdowns")
    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: For Widget

struct Provider: TimelineProvider {
    var moc = managedObjectContext

    init(context : NSManagedObjectContext) {
        self.moc = context
    }

    func placeholder(in context: Context) -> SimpleEntry {
        return SimpleEntry(date: Date())
    }

    func getSnapshot(in context: Context, completion: @escaping (SimpleEntry) -> ()) {
        let entry = SimpleEntry(date: Date())
        return completion(entry)
    }

    func getTimeline(in context: Context, completion: @escaping (Timeline<Entry>) -> ()) {
        var entries: [SimpleEntry] = []

        let currentDate = Date()
        let entryDate = Calendar.current.date(byAdding: .minute, value: 1, 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 CountdownsWidgetEntryView : View {
    var entry: Provider.Entry

    @FetchRequest(entity: Countdown.entity(), sortDescriptors: []) var countdowns: FetchedResults<Countdown>

    var body: some View {
        return (
            VStack {
                ForEach(countdowns, id: \.self) { (memoryItem: Countdown) in
                    Text(memoryItem.title ?? "Default title")
                }.environment(\.managedObjectContext, managedObjectContext)
                Text(entry.date, style: .time)
            }
        )
    }
}

@main
struct CountdownsWidget: Widget {
    let kind: String = "CountdownsWidget"

    var body: some WidgetConfiguration {
        StaticConfiguration(kind: kind, provider: Provider(context: managedObjectContext)) { entry in
            CountdownsWidgetEntryView(entry: entry)
                .environment(\.managedObjectContext, managedObjectContext)
        }
        .configurationDisplayName("My Widget")
        .description("This is an example widget.")
    }
}

struct CountdownsWidget_Previews: PreviewProvider {
    static var previews: some View {
        CountdownsWidgetEntryView(entry: SimpleEntry(date: Date()))
            .previewContext(WidgetPreviewContext(family: .systemSmall))
    }
}

person Timothy    schedule 30.09.2020    source источник
comment
Вы не можете использовать FetchRequest в представлениях виджетов. Они ничего не наблюдают. Вам необходимо передать данные в представление как Entry. Вот возможные примеры: Обновление текстовой метки времени каждую минуту в WidgetKit или Как убедиться, что представление WidgetKit показывает правильные результаты от @FetchRequest?   -  person pawello2222    schedule 30.09.2020
comment
Отвечает ли это на ваш вопрос? Получение данных из виджета CoreData для iOS 14   -  person pawello2222    schedule 09.11.2020


Ответы (1)


Просто вызовите execute в контексте управляемого объекта, и, поскольку вы используете частный контекст, убедитесь, что вы вызываете performBlock.

NSManagedObjectContext* moc = [self getManagedObjectContext];
 [moc performBlock:^{
    NSString *entityName = @"myEntity";
    NSFetchRequest *fRequest = [[NSFetchRequest alloc]initWithEntityName:entityName];
    NSPredicate *predicate = [NSPredicate predicateWithFormat: @"SELECT * FROM myEntity"];

    [fRequest setPredicate:predicate];
    NSError *error = nil;
    NSArray *results = [moc executeFetchRequest:fRequest error:&error];
 
}];
person the Reverend    schedule 13.11.2020