I have been using my SwiftUI app for a while and noticed that my widget started showing the placeholder instead of the actual widget in random times. For the placeholder widget I used template data and it isn’t meant to be displayed on the home screen. The comments left by the WidgetKit extension template stated that I shouldn’t do fetch requests in the placeholders, so I didn’t.
To create example items for placeholders or previews I created this function:
private func createExampleItem(_ count: Int = 1) -> [Birth] {
let childContext = NSManagedObjectContext(concurrencyType: .mainQueueConcurrencyType)
childContext.parent = PersistenceController.shared.container.viewContext
let exampleItem = Birth(context: childContext)
exampleItem.name = "John Doe"
exampleItem.date = Calendar.current.date(byAdding: .day, value: 10, to: Date())
do {
try childContext.save()
} catch {
print(error)
}
var arr: [Birth] = []
for _ in 1...count {
arr.append(exampleItem)
}
return arr
}
In this function I used childContexts so that my example data wasn’t saved to the actual viewContext.
Both my getSnapshot
and placeholder
functions use the createExampleItem
function so I actually don’t know if the widget displayed on the Home Screen is the snapshot or placeholder. I also can’t test to see which one it is since it displays the placeholder in random times. If this isn’t a known issue I will test and see if it’s the snapshot or placeholder being displayed no matter how long it takes.
I also tried refreshing the widgets through a button I put in the app but it doesn’t change anything.
Timeline Provider
struct Provider: IntentTimelineProvider {
var networkManager = NetworkManager()
func placeholder(in context: Context) -> SimpleEntry {
SimpleEntry(date: Date(), configuration: ConfigurationIntent(), items: createExampleItem(), itemCount: 1)
}
func getSnapshot(for configuration: ConfigurationIntent, in context: Context, completion: @escaping (Entry) -> Void) {
let date = Date()
var entry: SimpleEntry
entry = SimpleEntry(date: date, configuration: configuration, items: createExampleItem(), itemCount: 1)
completion(entry)
}
func getTimeline(for configuration: ConfigurationIntent, in context: Context, completion: @escaping (Timeline<SimpleEntry>) -> ()) {
networkManager.fetchDataAndFilter { items in
let entry = SimpleEntry(date: Date(), configuration: configuration, items: items, itemCount: items.count)
let timeline = Timeline(entries: [entry], policy: .atEnd)
completion(timeline)
}
}
}
Network Manager
class NetworkManager {
private func fetchData() throws -> [Birth] {
let context = PersistenceController.shared.container.viewContext
let request = Birth.fetchRequest()
let result = try context.fetch(request)
return result
}
func fetchDataAndFilter(completion: @escaping ([Birth]) -> Void) {
do {
let items = try self.fetchData()
let sorted = sortBirthItems(items: items, filter: true)
completion(sorted)
} catch {
print(error)
}
}
}