У меня есть приложение, использующее Core Data с CloudKit. Изменения синхронизируются между устройствами. Основная цель имеет возможность фоновых режимов с отмеченными удаленными уведомлениями. Основная цель и цель виджета имеют одну и ту же группу приложений, и обе имеют возможность iCloud с установленными службами CloudKit и одним и тем же контейнером в контейнерах.
Моя цель - отображать актуальные записи Core Data в представлении SwiftUI 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()
for hourOffset in 0 ..< 5 {
let entryDate = Calendar.current.date(byAdding: .minute, 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 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))
}
}
Но у меня проблема: допустим, у меня есть 3 Countdown
записи в основном приложении:
В начале просмотра виджета, как и ожидалось, в предварительном просмотре отображаются 3 записи (пользовательский интерфейс для добавления виджета). Но после того, как я добавляю виджет на главный экран, он не показывает Countdown
строк, только entry.date, style: .time
. При изменении записи на временной шкале строки также не отображаются. Я сделал картинку, чтобы лучше проиллюстрировать это:
Or:
В стартовом представлении виджета, как и ожидалось, отображаются 3 записи, но примерно через минуту, если я удалю или добавлю Countdown
записей в основном приложении, виджет все еще показывает 3 начальных значения, но я хочу, чтобы он отображался фактическое количество значений (для отражения изменений). Временная шкала entry.date, style .time
изменяется, отражается в виджете, но не в записях запроса.
Есть ли способ убедиться, что мой виджет показывает правильные результаты запроса на выборку? Спасибо.
func getCountdownsCount()
со временем. Например: в первый раз правильно, но после удаления строк в основном приложении - не обновляетсяcount
. - person Igor R.   schedule 21.09.2020getCountdownsCount()
каждый раз, когда представление перерисовывается (когда отображается новая запись на временной шкале). - person Igor R.   schedule 21.09.2020