#swift #swiftui #widgetkit
Вопрос:
У меня возникли проблемы с пониманием того, как заставить мой SwiftUI
пример модели данных работать с моим виджетом. Это работает в моем тестовом приложении просто отлично, я сразу же замечаю изменения. Когда я пытаюсь использовать виджет, я вижу, что данные печатаются в консоли, но в моем View
in не происходит никаких изменений WidgetKit
. Я использую ObservableObject
класс и @Published
переменные. Я попытался использовать a @StateObject
, @ObservedObject
и an @EnvironmentObject
, и те же результаты. Всегда приводит к тому, что сегодня нет игры. Моя модель данных Combine
связана, не уверен, имеет ли это какое-либо отношение к тому, почему я не вижу изменений данных в своих WidgetKit
. View
Пример работы приложения SwiftUI
struct ContentView: View {
@ObservedObject var data = CombineData()
@State private var showSortSheet: Bool = false
@State private var nhlTeams: TeamOrder = .NewYorkIslanders
var body: some View {
NavigationView {
VStack(alignment: .leading) {
if data.schedule?.dates.first != nil {
Text("Game today")
} else {
Text("No game today")
}
}
.listStyle(PlainListStyle())
.navigationBarTitle(Text(""), displayMode: .inline)
.navigationBarItems(leading: HStack {
Button(action: {
self.showSortSheet.toggle()
}) {
HStack {
Image(systemName: "arrow.up.arrow.down")
}
}
})
.actionSheet(isPresented: $showSortSheet) {
ActionSheet(title: Text("Teams:"), buttons: [TeamOrder.NewYorkIslanders, TeamOrder.MontrealCanadiens].map { method in
ActionSheet.Button.default(Text("(method.rawValue)")) {
self.nhlTeams = method
data.fetchSchedule(self.nhlTeams.rawValue)
print("(self.nhlTeams.rawValue)")
}
})
}
.onAppear {
data.fetchSchedule(self.nhlTeams.rawValue)
}
}
}
}
Пример виджета @StateObject
(без изменений данных)
struct ExampleEntryView : View {
var entry: Provider.Entry
@Environment(.widgetFamily) var widgetFamily
@StateObject var model = CombineData()
@ObservedObject var model = CombineData()
/*@EnvironmentObject private var model: CombineData*/
var body: some View {
VStack(alignment: .leading) {
if model.schedule?.dates.first != nil {
Text("Game today")
} else {
Text("No game today")
}
}
.onAppear {
model.fetchSchedule(entry.configuration.teams.rawValue) {
WidgetCenter.shared.reloadTimelines(ofKind: "NHL_Widget")
}
}
}
}
Пример виджета 2 TimelineEntry (без изменений данных)
struct SimpleEntry: TimelineEntry {
let date: Date
let configuration: ConfigurationIntent
let model: CombineData
}
struct Provider: IntentTimelineProvider {
func getTimeline(for configuration: ConfigurationIntent, in context: Context, completion: @escaping (Timeline<Entry>) -> ()) {
var entries: [SimpleEntry] = []
let currentDate = Date()
let model = CombineData()
let entryDate = Calendar.current.date(byAdding: .minute, value: 1, to: currentDate)!
let entry = SimpleEntry(date: entryDate, configuration: configuration, model: model)
entries.append(entry)
let timeline = Timeline(entries: entries, policy: .atEnd)
model.fetchSchedule(entry.configuration.teams.rawValue) {
completion(timeline)
}
}
}
struct ExampleEntryView : View {
var entry: Provider.Entry
@Environment(.widgetFamily) var widgetFamily
var body: some View {
VStack(alignment: .leading) {
if entry.model.schedule?.dates.first != nil {
Text("Game today")
} else {
Text("No game today")
}
}
}
}
Ответ №1:
Виджеты статичны, представление, которое вы предоставляете getTimeline
, будет отображаться как есть и не будет обновляться, поэтому вызов fetchSchedule
on onAppear
даже не будет выполнен. Как только вы запустите обработчик завершения getTimeline
, код больше не будет выполняться.
Чтобы отобразить данные в ваших виджетах , вам необходимо получить данные getTimeline
, создать представление, которое отображает данные с самого начала, и вернуть эту запись в обработчике завершения.
В вашем последнем примере я бы предложил вам создать свою запись в обработчике завершения model.fetchSchedule
и передать schedule
объект в ваше представление.
Комментарии:
1. Вы были абсолютно правы, спасибо, что указали мне правильное направление! Теперь это работает imgur.com/a/A5QzKaJ