Background: I've implemented a widget in a SwiftUI project. The main app allows people to see bus service schedules at all bus stops. They can 'favourite' buses at stops they use frequently. These favourites are stored locally using SwiftData. The widget allows users to view the schedule of the top 4 favourite buses in the widget.
I have implemented it such that every time there is a context.insert or context.delete in the main app, I subsequently call WidgetCenter.shared.reloadAllTimelines() so that the widgets content is updated with the latest favourites.
I've used an asynchronous Task within the body of the widget Timeline provider to get the entry and update the timeline.
Code within timeline provider:
@MainActor
func getTimeline(in context: Context, completion: @escaping (Timeline<Entry>) -> ()) {
Task{
//1.Get from Core Data
let faveServicesSaved = getFavourites()
print("Widget: Get Favourites Triggered \(faveServicesSaved.count)")
//Get arrival info
let faveServicesReturned = try? await fetchAllData(services: faveServicesSaved)
print("Widget: Arrival Data Retrieved \(faveServicesReturned?.count)")
//Sort by location
let faveServicesSorted = sortByLocation(faveServicesReturned ?? [])
print("Widget: Sorted by location \(faveServicesSorted.count)")
let nearestFaveServices = faveServicesSorted.prefix(4)
print("Widget: Nearest fave services \(nearestFaveServices.count)")
//choose the first 4 for display
let entry = Favourites(date: Date(), services: Array(nearestFaveServices))
let timeline = Timeline(entries: [entry], policy: .never)
completion(timeline)
}
}
//Since cannot access @Query from within Timeline provider, need to get info using Core Data
@MainActor
private func getFavourites() ->[FaveService]{
guard let container = try? ModelContainer(for: FaveService.self) else {
print("Widget: Problem with container setup")
return []
}
let descriptor = FetchDescriptor<FaveService>()
let faves = try? container.mainContext.fetch(descriptor)
print("Widget \(faves?.count)")
return faves ?? []
}
Problem: I find that the update to widget content is lagging by one update i.e. the first time I add a favourite from the main app it doesn't appear in the content. When I add the second favourite, the first one appears. When I add a third favourite, the second appears. etc.
What I've tried:
- As I mentioned, within the body of the main app I've double checked to ensure that reloadAllTimelines is being called after a context.insert.
- I've checked to ensure that all code is running on the main thread so there aren't any updating conflicts.
- I've checked that the model container is correctly setup for the first pull
- I've tried other update policies including .atEnd and .after(now.advance(by: 60)).
Any ideas what might be causing this lagged update?