I am trying to set two different times for Local Notifications - the default one being 10 am every day (if the user does not touch the date picker to pick their own notification time AKA it is nil), and one based on the user's input. The user input one does work and sends notifications every day, but if no time is chosen the default time does not work.
This is my code, can someone tell me what I am doing wrong? I basically want to check that if the user input is NIL it should revert to the default time set.
In settings:
IBOutlet var userDatePicker: UIDatePicker!
IBAction func pickerValueChanged(_ sender: UIDatePicker) {
var selectedTime = Date()
selectedTime = sender.date
// convert to data type DateComponents
let convertedSelectedTime = calendar.dateComponents([.hour, .minute,], from: selectedTime)
let delegate = UIApplication.shared.delegate as? AppDelegate
delegate?.sendNotification(with: convertedSelectedTime)
UserDefaults.standard.set(selectedTime, forKey: "SavedTime")
}
In AppDelegate:
func sendNotification(with userSelectedTime: DateComponents?) {
let center = UNUserNotificationCenter.current()
let content = UNMutableNotificationContent()
content.title = "Testing"
content.body = "testing"
var defaultTime = DateComponents()
defaultTime.hour = 10
defaultTime.minute = 00`// trying to set default time to 10 am if user never picks a time`
let components = userSelectedTime ?? defaultTime//option between the two
let trigger = UNCalendarNotificationTrigger(dateMatching: components, repeats: true)
let request = UNNotificationRequest(identifier: UUID().uuidString, content: content, trigger: trigger)
center.add(request)
}
Try this. All of its fields are optional. So you can use those you need.
DateComponents(calendar:timeZone:era:year:month:day:hour:minute:second:nanosecond:weekday:weekdayOrdinal:quarter:weekOfMonth:weekOfYear:yearForWeekOfYear:)
let triggerDaily = DateComponents(calendar: Calendar.current,
timeZone: Calendar.current.timeZone,
hour: 10, // Use 22 if PM
minute: 00,
second: 00,
nanosecond: 00)
let trigger = UNCalendarNotificationTrigger(dateMatching: triggerDaily, repeats: false)
In pickerValueChanged
, you are schedulling notification every time DatePicker
value is changed. That is bad. There you should only store date.
func pickerValueChanged(_ sender: UIDatePicker) {
UserDefaults.standard.set(sender.date, forKey: "SavedTime")
}
sendNotification
should only send notification.
func sendNotification(with dateComponents: DateComponents) {
let center = UNUserNotificationCenter.current()
let content = UNMutableNotificationContent()
content.title = "Testing"
content.body = "testing"
let trigger = UNCalendarNotificationTrigger(dateMatching: dateComponents, repeats: true)
let request = UNNotificationRequest(identifier: UUID().uuidString, content: content, trigger: trigger)
center.add(request)
}
UIApplication
has alife method that is called when an App goes to background. You can schedule notifications there.
func applicationDidEnterBackground(_ application: UIApplication) {
let date = UserDefaults.standard.value(forKey: "SavedTime") as? Date
if let date = date {
let convertedSelectedTime = Calendar.current.dateComponents([.hour, .minute,], from: date)
sendNotification(with: convertedSelectedTime)
} else {
let dateComponent = DateComponents(calendar: Calendar.current,
timeZone: Calendar.current.timeZone,
hour: 10, // Use 22 if PM
minute: 00,
second: 00,
nanosecond: 00)
sendNotification(with: dateComponent)
}
}
Use SavedTime
if it exists in UserDefaaults
. Else use 10:00
.
If you use SceneDelegate, use sceneDidEnterBackground
instead of applicationDidEnterBackground
func sceneDidEnterBackground(_ scene: UIScene) {
}
They both are life-cycle methods.