How to Detect Day Change in Swift

How to detect day change in Swift

You need to add an observer for "UIApplicationSignificantTimeChangeNotification":

NotificationCenter.default.addObserver(self, selector: #selector(dayChanged), name: UIApplicationSignificantTimeChangeNotification, object: nil)

For Swift 4.2 or later

NotificationCenter.default.addObserver(self, selector: #selector(dayChanged), name: UIApplication.significantTimeChangeNotification, object: nil)

Note: If your intent is to be notified when the day changes you can use .NSCalendarDayChanged ("NSCalendarDayChangedNotification") instead of UIApplication.significantTimeChangeNotification.

NotificationCenter.default.addObserver(self, selector: #selector(dayChanged), name: .NSCalendarDayChanged, object: nil)

And add the selector method to the view controller where you would like to monitor the day changes:

@objc func dayChanged(_ notification: Notification) {

}

Detecting Day Change in iOS App

Solution which saves an integer value (the day) in NSUserDefaults

  • In AppDelegate create a method checkDayChange which compares the day component of the current date with a saved value in NSUserDefaults (default is 0). If the values are not equal, call resetValues and save the current day.

    - (void)checkDayChange
    {
    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
    NSInteger currentDay = [[NSCalendar currentCalendar] component:NSCalendarUnitDay fromDate:[NSDate date]];
    NSInteger savedDay = [defaults integerForKey:@"day"]; // default is 0
    if (currentDay != savedDay) {
    [self resetValues];
    [defaults setInteger:currentDay forKey:@"day"];
    }
    }
  • Observe NSCalendarDayChangedNotification with selector checkDayChange

  • Call checkDayChange also in applicationDidFinishLaunching and applicationDidBecomeActive

Swift 3: Find out, if the date has changed - how?

You need to use Calendar method isDateInToday to check date is today's date. Also you need to put the code before returning value from function.

if !Calendar.current.isDateInToday(oldDate) {
defaults.set(Date(), forKey: "oldDate")
return true
}
return false

Checking when a date has passed - Swift

Implement to observe

NSCalendarDayChangedNotification

Posted whenever the calendar day of the system changes, as determined
by the system calendar, locale, and time zone. This notification does
not provide an object.

If the the device is asleep when the day changes, this notification
will be posted on wakeup. Only one notification will be posted on
wakeup if the device has been asleep for multiple days.

There are no guarantees about the timeliness of when this notification
will be received by observers. As such, you should not rely on this
notification being posted or received at any precise time.

The notification is posted through [NSNotificationCenter defaultCenter].

Example:

In applicationDidFinishLaunching add

NSNotificationCenter.defaultCenter().addObserver(self, selector:"calendarDayDidChange:", name:NSCalendarDayChangedNotification, object:nil)

and implement the method

func calendarDayDidChange(notification : NSNotification)
{
doSomethingWhenDayHasChanged()
}

or use the block API.

If the class including the observer is not the application delegate class you might remove the observer at some time.

How to check the date everyday in swiftUI

  1. You can use - (void)applicationSignificantTimeChange:(UIApplication *)application; in AppDelegate to monitor such changes.

  2. You can also register for a notification in AppDelegate UIApplication.significantTimeChangeNotification
    iOS will call both the registered notification method as well above delegate method.

       NotificationCenter.default.addObserver(self, selector: #selector(timeChanged), name: UIApplication.significantTimeChangeNotification , object: nil)
 @objc func timeChanged() {
print("App Time Changed")
}

  1. In case you want to hook up with your SwiftUI directly, you can register your Swift view with your publisher.
    Publisher will listen for notification name UIApplication.significantTimeChangeNotification.

Either of the ways can be used based on your requirement.

struct ContentView: View {
@State var dayDetails: String = "Hello World"
var body: some View {
Text(dayDetails)
.padding().onReceive(NotificationCenter.default.publisher(for: UIApplication.significantTimeChangeNotification), perform: { _ in
dayDetails = "Day has changed"
})
}
}

what's an efficient way in swift to get a change of day event

you could try something like this:
(note I did not wait to see if this works)

import SwiftUI
import Combine
#if os(iOS)
import UIKit
#endif

@main
struct TestApp: App {
var body: some Scene {
WindowGroup {
ContentView()
}
}
}

struct ContentView: View {
var body: some View {
Text("day change")
.onReceive(NotificationCenter.default.publisher(
for: UIApplication.significantTimeChangeNotification)) { _ in

print("----> day time has changed <----\n")

print("A notification that posts when there is a significant change in time, \n for example, change to a new day (midnight), \n carrier time update, and change to or from daylight savings time.")
}
}
}

Check if today is a new day SwiftUI

you could try something like this:

import SwiftUI

struct ContentView: View {
@State var lastDay: Date = Date()
@State var isToday = false
@State var selectedTime = 8 // 24 hour clock

var body: some View {
Text("your main view")
.onReceive(NotificationCenter.default.publisher(for: UIApplication.willResignActiveNotification)) { _ in
// store the date whenever you go into background
print("---> storing: \(Date())")
UserDefaults.standard.set(Date(), forKey: "lastDay")
}
.onReceive(NotificationCenter.default.publisher(for: UIApplication.willEnterForegroundNotification)) { _ in
// try to retrieve the date when you come back from background
print("\n----> try retrieve lastDay")
if let temDate = UserDefaults.standard.object(forKey: "lastDay") {
self.lastDay = temDate as! Date
print("----> retrieved lastDay: \(self.lastDay)")
if Calendar.current.isDate(Date(), inSameDayAs: self.lastDay) {
self.isToday = true
print("----> isToday: \(self.isToday)\n")
// if it is 8 am or later do something
if let thisHour = Calendar.current.dateComponents([.hour], from: Date()).hour {
if (thisHour >= self.selectedTime) {
print("----> it is 8am or later --> do something")
// self.doSomething()
}
}
}
}
}
}
}

NotificationCenter is Apple internal message system. SwiftUI can listen for specific events, like when the App goes into the background. This is what this line does:

.onReceive(NotificationCenter.default.publisher(for: UIApplication.willResignActiveNotification)) 

Now, this line:

 .onReceive(NotificationCenter.default.publisher(for: UIApplication.willEnterForegroundNotification)) 

listens for when you come back from the background, as mentioned in the comments.

There is no slowing down because of these onReceives.

What I have shown is an approach, you can add other .onReceive, such as:

.onReceive(NotificationCenter.default.publisher(for: UIApplication.didBecomeActiveNotification)) { _ in

.onReceive(NotificationCenter.default.publisher(for: UIApplication.willTerminateNotification)) { _ in

These can be used for when you start the App, and when you quit the App.



Related Topics



Leave a reply



Submit