问题
I am developing an application for ios 14 Home Widget and I am facing a problem while showing the current time (digital clock) that the widget not getting updated every sec. As we all know, Apple does not allow to trigger timeline every second is there any other way to display the current time with the realtime updates?
I tried these methods but not works as expected
class NetworkManager: ObservableObject {
@Published var dateIs = Date()
init() {
startTimer() // fetch data must be called at least once
}
private func startTimer() {
let t = RepeatingTimer(timeInterval: 3)
t.eventHandler = {
DispatchQueue.main.async() {
// your UI update code
print("Timer Fired")
self.dateIs = Date()
WidgetCenter.shared.reloadAllTimelines() // reload timelines
}
if(false){ //I know this makes no sense, but it works. Go figure...
t.suspend()
}
}
t.resume()
}
}
struct Provider: TimelineProvider {
init() {
networkManager = NetworkManager()
}
@AppStorage("storedData", store: UserDefaults(suiteName: "group.com.name"))
var data: Data = Data()
func placeholder(in context: Context) -> WidgetEntry {
let entry = WidgetEntry(date: Date(), storedData: storedData[0], dateIs: networkManager.dateIs)
return entry
}
func getSnapshot(in context: Context, completion: @escaping (WidgetEntry) -> Void) {
guard let storedData: WidgetTemplate = try? JSONDecoder().decode(WidgetTemplate.self, from: data) else { return }
let entry = WidgetEntry(date: Date(), storedData: storedData, dateIs: networkManager.dateIs)
completion(entry)
}
func getTimeline(in context: Context, completion: @escaping (Timeline<WidgetEntry>) -> Void) {
guard let storedData: WidgetTemplate = try? JSONDecoder().decode(WidgetTemplate.self, from: data) else { return }
let entry = WidgetEntry(date: Date(), storedData: storedData, dateIs: networkManager.dateIs)
let currentDate = Date()
let refreshDate = Calendar.current.date(byAdding: .minute, value: 5, to: currentDate)!
let timeline = Timeline(entries: [entry], policy: .after(refreshDate))
completion(timeline)
}
}
回答1:
You’re not allowed to refresh the Widget every second. That’s the limitation from Apple.
Best you can do is display a date with seconds
using the timer
date style:
/// A style displaying a date as timer counting from now.
///
/// Text(event.startDate, style: .timer)
///
/// Example output:
/// 2:32
/// 36:59:01
public static let timer: Text.DateStyle
- You need a simple
Entry
with aDate
property:
struct SimpleEntry: TimelineEntry {
let date: Date
}
- Pass the midnight date for a given day in the
Entry
and refresh the timeline after the next midnight:
struct SimpleProvider: TimelineProvider {
...
func getTimeline(in context: Context, completion: @escaping (Timeline<Entry>) -> Void) {
let midnight = Calendar.current.startOfDay(for: Date())
let nextMidnight = Calendar.current.date(byAdding: .day, value: 1, to: midnight)!
let entries = [SimpleEntry(date: midnight)]
let timeline = Timeline(entries: entries, policy: .after(nextMidnight))
completion(timeline)
}
}
- Display the date using the
timer
style:
struct SimpleWidgetEntryView: View {
var entry: SimpleProvider.Entry
var body: some View {
Text(entry.date, style: .timer)
}
}
Note that when you refresh the timeline (either by specifying the TimelineReloadPolicy
or by calling the WidgetCenter
) you set the earliest time when the Widget will be refreshed.
It is not guaranteed to be refreshed at that specific time.
来源:https://stackoverflow.com/questions/64053270/how-to-display-current-time-realtime-in-ios-14-home-widget