Learn Courses My Dashboard

Date doesn't change until app refreshes

I’m displaying today’s date in my app like this:

  @State private var today = Date()

  var dateFormatter: DateFormatter
  {
    let formatter = DateFormatter()
    formatter.dateStyle = .full
    return formatter
  }

 
  var body: some View
  {
    NavigationView
    {
      VStack
      {
        Text("Today is \(today, formatter: dateFormatter)")

This works fine until the next morning. When I start the app, it still displays yesterday’s date. As soon as I do something that causes the view to refresh, the correct date is displayed.

The calendar app doesn’t have this problem, so I know there’s a solution.

Can anyone help?

So when you use the App and you have finished with it, do you you remove it from running in the background? ie, do you

A: slowly slide your finger up from the bottom of the screen until the device switches into the tile mode (this allows you to switch between apps that are running in the background) and do you then remove the App from the background by swiping the App up or

B: do you just swipe your finger up from the bottom of the screen quickly and the device displays the Home screen view (or the App page you last launched an App from)?

The solution may be to add a timer to your App and then add an .onReceive() modifier to your NavigationView

For example, below your @State declaration add:

let timer = Timer.publish(every: 1, on: .main, in: .common).autoconnect()

This fires the timer at 1 second intervals.

Then in the body add this to the end of the NavigationView:

.onReceive(timer) { input in
    today = input
}

When I do B, the date doesn’t update. I have to do A to get the date correct. I would like the date to be correct when I start the app after doing B. The Calendar app does it the way I want.

Your suggestion looks interesting. Some questions:

Can I use a timer to activate my app at midnight?

Does “today = input” cause the view to refresh?

I believe the problem is that the main View is not activated when starting the app after B. I know this because I had a Print inside an .onAppear that didn’t Print when starting the app after B.

In any case, I’ll play with your suggestion and see how that works. Thanks.

P.S. I’m sure glad you designated those scenarios with A and B. :grinning:

The reason that the App does not update in scenario B is that all you are dong it pushing the App to the background and when you bring it back to the foreground there has been no change to the State of the App and consequently the view does not refresh.

You can pretty much assume that the Calendar App is constantly keeping track of the date and time in order to be able to send notifications that a calendar event is due that you have set to trigger at a specific date and time.

Can I use a timer to activate my app at midnight?

Probably but I don’t have enough knowledge about setting that kind of stuff up.

Does “today = input” cause the view to refresh?

Yes, that’s why I provided you with that code.
(edit) When you change a State property the view dates.

You could try updating the date when your app receives willEnterForegroundNotification. Attach something like this somewhere in your View hierarchy:

    .onReceive(NotificationCenter.default.publisher(for: UIApplication.willEnterForegroundNotification)) { _ in
        //update date here
    }

Good suggestion Patrick. :+1:

I added the code that Patrick (roosterboy) suggested. I was able to test it by initializing ‘today’ to tomorrow. When I started the app for the first time, tomorrow’s date was displayed. After I closed and opened the app, today’s date was displayed. This tells me at willEnterForegroundNotification isn’t called on initial app activation, but is called on subsequent activations. This is exactly what I was looking for.

Chris, thanks for your suggestion. I may not need it, but I learned about Timers. That has to come in handy in the future.