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.
- Add another property to your
TimelineEntry
, let’s call itclubName
:
struct SimpleEntry: TimelineEntry {
let date: Date
let clubName: String
}
- Update the
NetworkManager
and return results in thecompletion
:
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()
}
}
- Use the
NetworkManager
in theTimelineProvider
and create timelines entries when thefetchData
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)
}
}
}
- 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.