Why is significantTimeChangeNotification not emitted (or not received?)

Viewed 262

I'm very new to Swift. For learning purposes I'm creating a little countdown app (days until date X). Those countdowns are presented in a List. A single countdown in the list is represented by the following view.

struct CountdownRow: View {
  @State private var remainingDays: Int = 0
  @State private var progress: Float = 0.0
  
  var countdown: Countdown
  
  var body: some View {
    VStack{
      HStack {
        Text(countdown.name)
          .font(.subheadline)
          .multilineTextAlignment(.leading)
          .padding(10)
        Spacer()
        Text(String(remainingDays))
          .font(.headline)
          .padding(10)
      }
      ProgressView(value: progress)
        .padding(10)
    }
    .onAppear {
      remainingDays = countdown.getRemainingDays()
      progress = countdown.getProgress()
    }
    .onReceive(NotificationCenter.default.publisher(for:
        UIApplication.significantTimeChangeNotification), 
        perform: { _ in
      remainingDays = countdown.getRemainingDays()
      progress = countdown.getProgress()
    })
  }
}

I want to update the remaining days for each countdown at midnight. But the .onReceive modifier doesn't trigger when the time changes from 23:59 to 0:00. Receiving other notifications (e.g. UIApplication.willEnterForegroundNotification) instead works as expected.

Why is this specific notification not emitted (or received) at midnight? According to the documentation at apple, it should be emitted at midnight.

Thank you!

1 Answers

It is emitted at midnight if the app is in the foreground. Is your app in the foreground at midnight? Otherwise, you should check the time when your return to the foreground and update accordingly.

This is true of all NSNotifications. If your app is suspended, they won't be received. It's not a special situation for significantTimeChangeNotification.

willEnterForegroundNotification may appear special, but it's only sent in cases where your app has already been re-launched.

That said, I would highly recommend redesigning this so that Countdown is an ObservableObject, and that it updates itself at appropriate times (by observing significantTimeChangeNotification and willEnterForegroundNotification). Then you could just bind remainingDays and progress to it without needing onAppear or onReceive on the View.

Related