Post

Replies

Boosts

Views

Activity

How can I share SwiftData @Model between widget and app?
I have an App Group shared between my app and its widgets. I have SwiftData's @Model, updated from the widget intent's perform() method and displayed on the app and the widget. @MainActor func perform() async throws -> some IntentResult { let context = try ModelContainer(for: MyModel.self).mainContext let myModel = try ModelContainer(for: MyModel.self).mainContext.fetch( FetchDescriptor<MyModel>(predicate: #Predicate { // The predicate is not the problem. }) ).first myModel?.functionThatModifiesMyModel() return .result() } Both the app and the widget SwiftUI views access to the model using Macros. @Environment(\.modelContext) var context @Query(sort: \.whatever) var myModel: [MyModel] But the data is never correct in the app code (the widget's data is updated correctly using the intent). Why doesn't the model make it to the app?
4
0
1.5k
Jul ’23
Why don't interactive buttons in iOS 17 widget call AppIntent perform() when the app running?
Inside a widget, there is a button, Button(intent: AnAppIntent()) { // Button's label. } // It seems this modifier does not add any value. .invalidatableContent() connected to an AppIntent. struct AnAppIntent: AppIntent { static var title: LocalizedStringResource = "An AppIntent" init() { // AppIntent required init. } func perform() async throws -> some IntentResult { // Never called when the app is running. return .result() } } The button calls AppIntent's perform() when tapped, and it consequently updates the widget UI (with or without the modifier .invalidatableContent()) only when the app is closed completely. If the app is alive in the background, perform() is not called, and the widget UI never updates. The user must explicitly dismiss the app to make the widget work as expected. The problem may be in the timeline used. struct SimpleEntry: TimelineEntry { let date: Date } struct Provider: TimelineProvider { func placeholder(in context: Context) -> SimpleEntry { SimpleEntry(date: Date()) } func getSnapshot(in context: Context, completion: @escaping (SimpleEntry) -> ()) { completion(SimpleEntry(date: Date())) } func getTimeline(in context: Context, completion: @escaping (Timeline<Entry>) -> ()) { var entries: [SimpleEntry] = [] // Generate a timeline 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: .second, value: hourOffset, to: currentDate)! entries.append(SimpleEntry(date: entryDate)) } let timeline = Timeline(entries: entries, policy: .atEnd) completion(timeline) } } However, if the problem were the timeline, the widget would not work with the app dismissed. Any idea on how to keep interactive widgets always working?
2
1
2.3k
Jun ’23