How to refresh Widget data?

You can’t use the ObservedObject like you’d normally use in your App.

In Widgets you use a TimelineProvider which creates an Entry for your view.


  1. Add another property to your TimelineEntry, let’s call it clubName:
struct SimpleEntry: TimelineEntry {
    let date: Date
    let clubName: String
}
  1. Update the NetworkManager and return results in the completion:
class NetworkManager {
    func fetchData(completion: @escaping ([Post]) -> Void) {
        ...
        URLSession(configuration: .default).dataTask(with: url) { data, _, error in
            ...
            let result = try JSONDecoder().decode(Results.self, from: data)
            completion(result.data)
            ...
        }
        .resume()
    }
}
  1. Use the NetworkManager in the TimelineProvider and create timelines entries when the fetchData completes:
struct Provider: TimelineProvider {
    var networkManager = NetworkManager()

    func placeholder(in context: Context) -> SimpleEntry {
        SimpleEntry(date: Date(), clubName: "Club name")
    }

    func getSnapshot(in context: Context, completion: @escaping (SimpleEntry) -> Void) {
        let entry = SimpleEntry(date: Date(), clubName: "Club name")
        completion(entry)
    }

    func getTimeline(in context: Context, completion: @escaping (Timeline<Entry>) -> Void) {
        networkManager.fetchData { posts in
            let entries = [
                SimpleEntry(date: Date(), clubName: posts[0].home_name)
            ]
            let timeline = Timeline(entries: entries, policy: .never)
            completion(timeline)
        }
    }
}
  1. Use entry.clubName in the view body:
struct WidgetNeuEntryView: View {
    var entry: Provider.Entry

    var body: some View {
        VStack {
            Text(entry.date, style: .time)
            Text("Club: \(entry.clubName)")
        }
    }
}

Note that in the above example the reload policy is set to never to only load the data once.

You can easily change it to atEnd or after(date:) if you want to reload the timeline automatically.

If you need to reload the timeline manually at any point you can just call:

WidgetCenter.shared.reloadAllTimelines()

This will work in both App and Widget.


Here is a GitHub repository with different Widget examples including the Network Widget.

Leave a Comment