How to use Timer in the new Widget API?

I'm building a new widget for one of my apps, and the new Text initializer init(_:style:) is not enough for me. I need to have some control over which NSCalendar.Units are displayed, so I'm trying to use DateComponentsFormatter here. I have to use my own Timer because of that, and here's my code.
Code Block swift
struct TimerText: View {
    let date: Date
    let allDay: Bool
    let unitFlags: NSCalendar.Unit
    private let timer = Timer.publish(every: 1, on: .main, in: .common).autoconnect()
    @State var duration: String?
    init(date: Date, allDay: Bool, unitFlags: NSCalendar.Unit) {
        self.date = date
        self.allDay = allDay
        self.unitFlags = unitFlags
        updateDuration()
    }
    func updateDuration() {
        duration = systemDurationString(date, allDay: allDay, unitFlags: unitFlags)
    }
    var body: some View {
        Text(duration ?? "—")
            .font(.system(.title, design: .monospaced))
            .onReceive(timer) { _ in
                updateDuration()
            }
    }
}

systemDurationString function uses DateComponentsFormatter inside and returns the formatted string.
Unfortunately, onReceive callback never gets called. I thought this might be a problem with RunLoop that I've chosen, but it's seems like .current doesn't work either.

Replies

Hi, you cannot use dynamic data in your widget. The relative date Text initializer is special. Your timer will never be called because that View is only used one time per entry.
I wish there was a way to set unit flags for this custom Text initialiser. Without that the way I present data in the app will be different from the way I present data in the widget which is kinda bad for users. Anyway, thank you for your answer!