Notifications not popping up on selected days of week - ios

i am working on an alarm app in which user can select days of week on which he wants to ring the alarm. In my code if I'm executing the condition for "same day" only then alarm is ringing on every day. But when I'm selecting the other two conditions i.e. "Next day" and "Previous day", notifications are not firing. Although the notifications are created but they are not firing. Any help would be appreciated. Here's my code
func scheduleUserNotifications(for alarm: Alarm)
{
let notificationContent = UNMutableNotificationContent()
notificationContent.title = "HelloK"
if alarm.name.isEmpty == false
{
notificationContent.body = "Please respond to your alarm \(alarm.name)"
}
else
{
alarm.name = "Empty"
}
let song = AlarmController.shared.tone
print (song)
notificationContent.sound = UNNotificationSound(named: song)
print(notificationContent.sound)
print(AlarmController.shared.counter)
var countNum: Int!
if AlarmController.shared.counter == "30 Minutes"
{
countNum = 6
}
else if AlarmController.shared.counter == "1 Hour"
{
countNum = 12
}
else
{
countNum = 36
}
print(countNum)
var daysValue: [Int]
daysValue = AlarmController.shared.days
print(daysValue)
var dateVal = 0
for day in daysValue
{
print(dateVal)
if day == 1
{
print("hello")
guard let fireDate = alarm.fireDate else { return }
print(fireDate)
let dateToChange = fireDate
var nextDate = dateToChange
var difference : Int?
// var addComponent : Calendar.Component?
let weekday = Calendar.current.component(.weekday, from: fireDate)
print(weekday)
if dateVal == weekday-1
{
print("same day")
nextDate = fireDate
// nextDate = fireDate.addingTimeInterval(7*86400)
print(nextDate)
}
else if dateVal > weekday-1
{
print("next day")
difference = dateVal - (weekday-1)
print(difference!)
nextDate = fireDate.addingTimeInterval(TimeInterval(difference!*86400))
print(nextDate)
}
else if dateVal < weekday-1
{
print("previous day")
difference = 7-(weekday-1)+dateVal
print(difference!)
nextDate = fireDate.addingTimeInterval(TimeInterval(difference!*86400))
print(nextDate)
}
for ind in 0...countNum
{
let date = nextDate.addingTimeInterval((1.0*Double(ind)) * 60.0)
print(date)
let triggerDate = Calendar.current.dateComponents([.weekday, .hour, .minute, .second], from: date)
DispatchQueue.main.async
{
print(triggerDate)
let trigger = UNCalendarNotificationTrigger(dateMatching: triggerDate, repeats: true)
let request = UNNotificationRequest(identifier: "\(alarm.uuid)\(ind)", content: notificationContent, trigger: trigger)
// print(request)
UNUserNotificationCenter.current().add(request)
{
(error) in
if let error = error
{
print("Unable to add notification request, \(error.localizedDescription)")
}
}
}
}
}
dateVal += 1
}
let center = UNUserNotificationCenter.current()
center.getPendingNotificationRequests { (notifications) in
print("Count: \(notifications.count)")
for item in notifications {
print(item.content)
}
}
}
when I remove this part of my code, notifications are working fine but they are firing on every day
else if dateVal > weekday-1
{
print("next day")
difference = dateVal - (weekday-1)
print(difference!)
nextDate = fireDate.addingTimeInterval(TimeInterval(difference!*86400))
print(nextDate)
}
else if dateVal < weekday-1
{
print("previous day")
difference = 7-(weekday-1)+dateVal
print(difference!)
nextDate = fireDate.addingTimeInterval(TimeInterval(difference!*86400))
print(nextDate)
}
but when i uncomment it, no notification appears

Related

Send a local notification when timer is up

I would like to send a local notification once 24 hours has passed after a button is selected. The button is currently only enabled once 24 hours has passed and the waiting time is saved in UserDegaults. I would like to know how I will be able to send a local notification to the user automatically once the 24 hours has passed.
func getNextQuote(){
let defaults = UserDefaults.standard
defaults.integer(forKey: "savedIndexKey")
let currentIndex = defaults.integer(forKey: "savedIndexKey")
var nextIndex = currentIndex+1
nextIndex = quotes.indices.contains(nextIndex) ? nextIndex : 0
defaults.set(nextIndex, forKey: "savedIndexKey")
let savedInteger = defaults.integer(forKey: "savedIndexKey")
saved = savedInteger
quotesLabel.text = quotes[savedInteger]
self.quotesLabel.fadeIn()
set24HrTimer()
update()
}
func update(){
if let waitingDate = UserDefaults.standard.value(forKey: "waitingDate") as? Date{
if let waitingDate = UserDefaults.standard.object(forKey: "waitingDate") as? Date,
waitingDate < Date() {
self.timeLabel.text = "Please check in for the day"
self.remainingLabel.text = "Did you stay clean today?"
self.remainingLabel.font = UIFont(name: "Arial", size: 32)
self.quotesLabel.isHidden = true
addButton.isHidden = false
noButton.isHidden = false
gridButton.isHidden = false
self.view.setNeedsDisplay()
print("time is up")
}else if let waitingDate = UserDefaults.standard.value(forKey: "waitingDate") as? Date {
self.timeLabel.attributedText = self.timeLeftExtended(date: waitingDate)
addButton.isHidden = true
noButton.isHidden = true
gridButton.isHidden = true
self.quotesLabel.isHidden = false
self.remainingLabel.text = "Until next check in"
self.quotesLabel.fadeIn()
print("still running")
}else{
let newDate = Calendar.current.date(byAdding: .hour, value: 24, to: Date())
UserDefaults.standard.set(newDate, forKey: "waitingDate")
self.timeLabel.attributedText = self.timeLeftExtended(date: newDate!)
print("last option")
}
}
}
func set24HrTimer() {
let currentDate = Date()
let newDate = Date(timeInterval: 86400, since: currentDate as Date)
UserDefaults.standard.setValue(newDate, forKey: "waitingDate")
print("24 hours started")
}
func timeLeftExtended(date:Date) ->NSAttributedString{
let cal = Calendar.current
let now = Date()
let calendarUnits:NSCalendar.Unit = [NSCalendar.Unit.hour, NSCalendar.Unit.minute, NSCalendar.Unit.second]
let components = cal.dateComponents([.hour, .minute, .second], from: now, to: date)
let fullCountDownStr = "\(components.hour!)h \(components.minute!)m \(components.second!)s "
let mutableStr = NSMutableAttributedString(string: fullCountDownStr, attributes: [NSAttributedString.Key.foregroundColor:UIColor.white])
for (index, char) in mutableStr.string.enumerated()
{
if(char == "h" || char == "m" || char == "s")
{
mutableStr.removeAttribute(NSAttributedString.Key.foregroundColor, range: NSMakeRange(index, 1))
mutableStr.addAttributes([NSAttributedString.Key.foregroundColor : UIColor.lightGray], range: NSMakeRange(index, 1))
}
}
return mutableStr
}
func setupTimer()
{
if(!timeWorking)
{
timer = Timer.scheduledTimer(timeInterval: 1.0, target: self, selector: #selector(self.updateCountDown), userInfo: nil, repeats: true)
self.timeWorking = true
}
}
You shouldn't use a timer to trigger a local notification. This function could be added as an extension to UIViewController that will let you create a UNCalendarNotificationTrigger:
import UserNotifications
import UIKit
extension UIViewController {
func createLocalNotification(title: String, hours: Int) {
let seconds = hours * 3600
let content = UNMutableNotificationContent()
content.sound = UNNotificationSound.default
content.title = title
let nextTriggerDate = Calendar.current.date(byAdding: .second, value: seconds, to: Date())!
let comps = Calendar.current.dateComponents([.year, .month, .day, .hour, .minute, .second], from: nextTriggerDate)
let trigger = UNCalendarNotificationTrigger(dateMatching: comps, repeats: false)
let request = UNNotificationRequest(identifier: "\(seconds)", content: content, trigger: trigger)
UNUserNotificationCenter.current().add(request, withCompletionHandler: nil)
}
}
And can be used within your UIViewController as follows:
let MyViewController: UIViewController {
#IBAction func buttonPressed(_ sender: Any) {
self.createLocalNotification(title: "24 hours have passed!", hours: 24)
}
}

Check if countdown has reached zero and update UILabel

I have a UILabel which displays my current 24 hour countdown. I would like to check if the countdown is at zero and when it is to update my UILabel. The way it is set up now if it is reached 24 hours it keeps running as negative numbers. For example -1h-55m-54s
I have tried to check if UILabel contains "-" and also if the value is less than 0 however have not got it to work.
func timeLeftExtended(date:Date) ->NSAttributedString{
let cal = Calendar.current
let now = Date()
let calendarUnits:NSCalendar.Unit = [NSCalendar.Unit.hour, NSCalendar.Unit.minute, NSCalendar.Unit.second]
let components = (cal as NSCalendar).components(calendarUnits, from: now, to: date, options: [])
let fullCountDownStr = "\(components.hour!.description)h " + "\(components.minute!.description)m " + "\(components.second!.description)s "
let mutableStr = NSMutableAttributedString(string: fullCountDownStr, attributes: [NSAttributedString.Key.foregroundColor:UIColor.white])
for (index, char) in mutableStr.string.enumerated()
{
if(char == "h" || char == "m" || char == "s")
{
mutableStr.removeAttribute(NSAttributedString.Key.foregroundColor, range: NSMakeRange(index, 1))
mutableStr.addAttributes([NSAttributedString.Key.foregroundColor : UIColor.lightGray], range: NSMakeRange(index, 1))
}
}
return mutableStr
}
func updateCountDown() {
if let waitingDate = UserDefaults.standard.value(forKey: "waitingDate") as? Date {
if let waitingDate = UserDefaults.standard.object(forKey: "waitingDate") as? Date,
waitingDate < Date() {
self.timeLabel.text = "Time ran out"
print("It is time for you to check in")
}
// if self.timeLeftExtended(date: waitingDate) <= 0{
//change label
}
self.timeLabel.attributedText = self.timeLeftExtended(date: waitingDate)
} else {
let newDate = Calendar.current.date(byAdding: .hour, value: 24, to: Date())
UserDefaults.standard.set(newDate, forKey: "waitingDate")
self.timeLabel.attributedText = self.timeLeftExtended(date: newDate!)
}
}
Just compare the dates
if let waitingDate = UserDefaults.standard.object(forKey: "waitingDate") as? Date,
waitingDate < Date() {
// waitingDate exists and is earlier than the current date
}
And you can create the countdown string much shorter
let components = cal.dateComponents([.hour, .minute, .second], from: now, to: date)
let fullCountDownStr = "\(components.hour!)h \(components.minute!)m \(components.second!)s "
Here is how I use UILabel to display count down timer
First, these are my variables
#IBOutlet weak var lblCountDownTime: UILabel! //label to display count down
var countDownTimer: Timer? // timer to count down
Second, this is how I display count down, hope it help
self.countDownTimer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(self.countDownTime), userInfo: nil, repeats: true);
func countDownTime() {
let now = Date();
let calendar = Calendar.current;
let comps = calendar.dateComponents(Set<Calendar.Component>([.minute, .second]), from: now, to: self.startTime);
var strMinute = "\(comps.minute!)";
var strSecond = "\(comps.second!)";
if (comps.minute! < 10) {
strMinute = "0\(comps.minute!)";
}
if (comps.second! < 10) {
strSecond = "0\(comps.second!)";
}
if (comps.minute! <= 0 && comps.second! <= 0) {
self.countDownTimer?.invalidate();
}
else {
self.lblCountDownTime.text = "\(strMinute):\(strSecond)\"";
}
}

How to display 24 hour counter once button is pressed

Once my button is pressed I would like to disable my button for 24 hours and displaying a countdown on a label display a countdown until the button will be active again.
I have saved the waiting date and compared it to current date but I am not sure how to display the countdown of how much time is left in hours, minutes, and seconds.
let todaysDate = Date()
func set24HrTimer() {
let currentDate = Date()
let newDate = Date(timeInterval: 86400, since: currentDate as Date)
UserDefaults.standard.set(newDate, forKey: "waitingDate")
print("24 hours started")
//disable the button
}
if let waitingDate:Date = UserDefaults.standard.value(forKey: "waitingDate") as? Date {
if (todaysDate.compare(waitingDate as Date) == ComparisonResult.orderedDescending) {
print("show button")
}
else {
print("hide button")
}
}
You can add following code to create time countdown.
First add two variable ass follow:
fileprivate var timeWorking : Bool = false // To check is timer already scheduled
var timer:Timer? // Instance of timer
Then add following code which will calculate remaining hour, minute and second.
func timeLeftExtended(date:Date) ->NSAttributedString{
let cal = Calendar.current
let now = Date()
let calendarUnits:NSCalendar.Unit = [NSCalendar.Unit.hour, NSCalendar.Unit.minute, NSCalendar.Unit.second]
let components = (cal as NSCalendar).components(calendarUnits, from: now, to: date, options: [])
let fullCountDownStr = "\(components.hour!.description)h " + "\(components.minute!.description)m " + "\(components.second!.description)s "
let mutableStr = NSMutableAttributedString(string: fullCountDownStr, attributes: [NSAttributedString.Key.foregroundColor:UIColor.white])
for (index, char) in mutableStr.string.enumerated()
{
if(char == "h" || char == "m" || char == "s")
{
mutableStr.removeAttribute(NSAttributedString.Key.foregroundColor, range: NSMakeRange(index, 1))
mutableStr.addAttributes([NSAttributedString.Key.foregroundColor : UIColor.lightGray], range: NSMakeRange(index, 1))
}
}
return mutableStr
}
Next, add code which is scheduledTimer if not scheduled.
func setupTimer()
{
if(!timeWorking)
{
timer = Timer.scheduledTimer(timeInterval: 1.0, target: self, selector: #selector(self.updateCountDown), userInfo: nil, repeats: true)
self.timeWorking = true
}
}
Add code to display count down in label.
#objc func updateCountDown()
{
if let waitingDate = UserDefaults.standard.value(forKey: "waitingDate") as? Date {
self.labelCountDown.attributedText = self.timeLeftExtended(date: waitingDate)
} else {
let newDate = Calendar.current.date(byAdding: .hour, value: 24, to: Date())
UserDefaults.standard.set(newDate, forKey: "waitingDate")
self.labelCountDown.attributedText = self.timeLeftExtended(date: newDate!)
}
}
Call setupTimer() method to continue timer.
Output:

How to unwrap an optional into a variable and then use that variable in the next iteration of a while loop?

I have a method below called createNotifications() in which I try to do some fancy stuff when the recurrence of an alarm is daily. I first call self.createNotificationForToday(), which goes fine, and then start a while loop and call self.createNotificationForTomorrowAndReturnNewDateComponents() in each iteration, each time returning the new date components and using it as the input for the next iteration. This allows me to call one method each time and every time, iterate to "tomorrow" and create a notification for that day. The problem is with this part:
var newDateComponents = dateComponents
while numberOfCreatableNotifications > 0 {
guard var newDateComponents = self.createNotificationForTomorrowAndReturnNewDateComponents(dateComponents: newDateComponents) else {
os_log("Could not unwrap newDateComponents in createNotifications() in Alarm.swift", log: OSLog.default, type: .debug)
return
}
numberOfCreatableNotifications = numberOfCreatableNotifications - 1
}
What I'm attempting to do is reinitialize the newDateComponents variable each time I go through the while loop and call the createNotificationForTomorrowAnd...() method, and use those newDateComponents as input for the next call to that method. Is there something fundamentally wrong with how I'm trying to do this? Is there a better way?
createNotifications():
private func createNotifications(dateComponents: DateComponents) {
if recurrence == .today {
createNotificationForToday(dateComponents: dateComponents)
} else if recurrence == .tomorrow {
let _ = createNotificationForTomorrowAndReturnNewDateComponents(dateComponents: dateComponents)
} else if recurrence == .daily {
let center = UNUserNotificationCenter.current()
center.getPendingNotificationRequests { (notifications) in
var numberOfCreatableNotifications = 64 - notifications.count
self.createNotificationForToday(dateComponents: dateComponents)
var newDateComponents = dateComponents
while numberOfCreatableNotifications > 0 {
guard var newDateComponents =
self.createNotificationForTomorrowAndReturnNewDateComponents(dateComponents: newDateComponents) else {
os_log("Could not unwrap newDateComponents in createNotifications() in Alarm.swift", log: OSLog.default, type: .debug)
return
}
numberOfCreatableNotifications = numberOfCreatableNotifications - 1
}
}
} else {}
}
createNotificationForToday():
private func createNotificationForToday(dateComponents: DateComponents) {
let center = UNUserNotificationCenter.current()
let content = UNMutableNotificationContent()
content.title = "Random Alarm"
content.subtitle = "It's time!"
content.body = self.note
content.sound = UNNotificationSound.default
let trigger = UNCalendarNotificationTrigger(dateMatching: dateComponents, repeats: false)
let uuidString = UUID().uuidString
let request = UNNotificationRequest(identifier: uuidString, content: content, trigger: trigger)
center.add(request) { (error) in
if error != nil {
print("error \(String(describing: error))")
}
}
}
createNotificationForTomorrowAndReturnNewDateComponents():
private func createNotificationForTomorrowAndReturnNewDateComponents(dateComponents: DateComponents) -> DateComponents? {
let center = UNUserNotificationCenter.current()
let content = UNMutableNotificationContent()
content.title = "Random Alarm"
content.subtitle = "It's time!"
content.body = self.note
content.sound = UNNotificationSound.default
let calendar = Calendar.current
guard let date = calendar.date(from: dateComponents) else {
os_log("Could not unwrap date in createNotificationForTomorrow() in Alarm.swift", log: OSLog.default, type: .debug)
return nil
}
guard let tomorrow = calendar.date(byAdding: .day, value: 1, to: date) else {
os_log("Could not unwrap tomorrow in createNotificationForTomorrow() in Alarm.swift", log: OSLog.default, type: .debug)
return nil
}
let newDateComponents = calendar.dateComponents([.year, .month, .day, .timeZone, .hour, .minute], from: tomorrow)
let trigger = UNCalendarNotificationTrigger(dateMatching: newDateComponents, repeats: false)
let uuidString = UUID().uuidString
let request = UNNotificationRequest(identifier: uuidString, content: content, trigger: trigger)
center.add(request) { (error) in
if error != nil {
print("error \(String(describing: error))")
}
}
return newDateComponents
}
The scope of a variable created by a guard statement is the block that contains the guard statement, which is the body of your while loop.
This means that the newDateComponents you are creating with your guard statement is not the same as the newDateComponents you created outside the while and the inner newDateComponents will be discarded after each iteration of the while loop.
You don't actually need the guard statement; you can build the unwrap into your while:
var newDateComponents: DateComponents? = dateComponents
while numberOfCreatableNotifications > 0, let currentDateComponents = newDateComponents {
newDateComponents = self.createNotificationForTomorrowAndReturnNewDateComponents(dateComponents: currentDateComponents)
numberOfCreatableNotifications -= 1
}
if numberOfCreateableNotifications > 0 {
os_log("Could not create all notifications
}
You can probably refactor this to be a bit more efficient and have one less function:
Use a Calendar property so that you don't need to keep instantiating the calendar
Have a function to return "tomorrow"
Have a function to schedule a notification
let calendar = Calendar.autoUpdatingCurrent
private func createNotifications(dateComponents: DateComponents) {
switch (recurrence) {
case .today:
createNotification(for: dateComponents)
case .tomorrow:
createNotification(for: day(after: dateComponents))
case .daily:
let center = UNUserNotificationCenter.current()
center.getPendingNotificationRequests { (notifications) in
var numberOfCreatableNotifications = 64 - notifications.count
var currentDay: DateComponents? = dateComponents
while numberOfCreatableNotifications > 0, current = currentDay {
createNotification(for: current)
currentDay = day(after: current)
numberOfCreateableNotification -= 1
}
if numberOfCreateableNotifications > 0 {
os_log("Could not create all notifications", type: .debug)
}
}
}
}
private func createNotification(for dateComponents: DateComponents) {
let center = UNUserNotificationCenter.current()
let content = UNMutableNotificationContent()
content.title = "Random Alarm"
content.subtitle = "It's time!"
content.body = self.note
content.sound = UNNotificationSound.default
let trigger = UNCalendarNotificationTrigger(dateMatching: dateComponents, repeats: false)
let uuidString = UUID().uuidString
let request = UNNotificationRequest(identifier: uuidString, content: content, trigger: trigger)
center.add(request) { (error) in
if let err = error {
print("error \(err.localizedDescription)")
}
}
}
private func day(after dateComponents: DateComponents) -> DateComponents? {
guard let date = calendar.date(from: dateComponents),
let tomorrow = calendar.date(byAdding: .day, value: 1, to: date)
else {
os_log("Could not calculate tomorrow in Alarm.swift", log: OSLog.default, type: .debug)
return nil
}
let newDateComponents = calendar.dateComponents([.year, .month, .day, .timeZone, .hour, .minute], from: tomorrow)
return newDateComponents
}
One final note, it would probably be nicer to pass Date instances rather than DateComponent instances and convert to DateComponent once when you need to actually schedule the notification.
You cannot directly bind to the variable newDateComponents from the
outer scope in the guard-statement. You can bind to a new variable and
then assign that to newDateComponents:
var newDateComponents = dateComponents
while numberOfCreatableNotifications > 0 {
guard let nextDateComponents =
self.createNotificationForTomorrowAndReturnNewDateComponents(dateComponents: newDateComponents) else {
os_log("Could not unwrap newDateComponents in createNotifications() in Alarm.swift", log: OSLog.default, type: .debug)
return
}
newDateComponents = nextDateComponents
numberOfCreatableNotifications = numberOfCreatableNotifications - 1
}

Triggering a weekly notification in swift 3 using local notifications api

I want to trigger a weekly notification that goes on Mondays at 7:00pm.
I see code like this:
let triggerWeekly = Calendar.current.dateComponents([.weekday, .hour, .minute, .second], from: date)
let trigger = UNCalendarNotificationTrigger(dateMatching: triggerWeekly, repeats: true)
What should I set the from date as?
Also does the date need to be in the present?
I am using iOS 10+ and swift 3.
Pass date which you want to generate local notification
let strDate = (data as AnyObject).value(forKey: "not_date") as? String
let dateformatter = DateFormatter()
dateformatter.dateFormat = "yyyy-MM-dd hh:mm a"
let notidate = dateformatter.date(from: strDate!)
you need to first stattnotificationdate like = 2018-06-25 07:00 PM after you need to add time interval
var dateStart = Date()
dateStart = dateStart.addingTimeInterval(TimeInterval(604800))
and generate notification with these interwal
//MARK:- Schedule Notification with Daily bases.
func scheduleNotification(at date: Date, body: String, titles:String) {
let triggerDaily = Calendar.current.dateComponents([.year, .month, .day, .hour, .minute, .second], from: date)
if #available(iOS 10.0, *) {
let trigger = UNCalendarNotificationTrigger(dateMatching: triggerDaily, repeats: true)
let content = UNMutableNotificationContent()
content.title = titles
content.body = body
content.sound = UNNotificationSound.default()
content.categoryIdentifier = "HardikBar"
let request = UNNotificationRequest(identifier: "NotificationAt-\(date))", content: content, trigger: trigger)
UNUserNotificationCenter.current().add(request) {(error) in
if let error = error {
print("Uh oh! We had an error: \(error)")
}
}
} else {
// Fallback on earlier versions
}
}
I have used below extension for Date:
extension Date {
static func today() -> Date {
return Date()
}
func next(_ weekday: Weekday, considerToday: Bool = false) -> Date {
return get(.Next,
weekday,
considerToday: considerToday)
}
func previous(_ weekday: Weekday, considerToday: Bool = false) -> Date {
return get(.Previous,
weekday,
considerToday: considerToday)
}
func get(_ direction: SearchDirection,
_ weekDay: Weekday,
considerToday consider: Bool = false) -> Date {
let dayName = weekDay.rawValue
let weekdaysName = getWeekDaysInEnglish().map { $0.lowercased() }
assert(weekdaysName.contains(dayName), "weekday symbol should be in form \(weekdaysName)")
let searchWeekdayIndex = weekdaysName.index(of: dayName)! + 1
let calendar = Calendar(identifier: .gregorian)
if consider && calendar.component(.weekday, from: self) == searchWeekdayIndex {
return self
}
var nextDateComponent = DateComponents()
nextDateComponent.weekday = searchWeekdayIndex
let date = calendar.nextDate(after: self,
matching: nextDateComponent,
matchingPolicy: .nextTime,
direction: direction.calendarSearchDirection)
return date!
}
}
This can be used for getting any next or previous weekday from the reference date. You'll need to get the next Monday first and then set the UNCalendarNotificationTrigger as below:
var triggerDaily = Calendar.current.dateComponents([.year, .month, .day, .hour, .minute, .second], from: Date().next(Date.Weekday.monday, considerToday: true))
triggerDaily.hour = 19
triggerDaily.minute = 0
triggerDaily.second = 0
if #available(iOS 10.0, *) {
let trigger = UNCalendarNotificationTrigger(dateMatching: triggerDaily, repeats: true)
let content = UNMutableNotificationContent()
content.title = "Title"
content.body = "Body"
content.sound = UNNotificationSound.default()
content.categoryIdentifier = "Test"
let request = UNNotificationRequest(identifier: "NotificationAt-\(String(describing: Calendar.current.date(from: triggerDaily))))", content: content, trigger: trigger)
UNUserNotificationCenter.current().add(request) {(error) in
if let error = error {
print("Uh oh! We had an error: \(error)")
}else {
UNUserNotificationCenter.current().getPendingNotificationRequests(completionHandler: { (arrayRequests) in
for request in arrayRequests {
if let calendarNotificationTrigger = request.trigger as? UNCalendarNotificationTrigger,
let nextTriggerDate = calendarNotificationTrigger.nextTriggerDate() {
print("nextTriggerDate ===>>> \(nextTriggerDate)")
}
print("Request ===>>> \(String(describing: request.trigger))")
}
})
}
}
} else {
// Fallback on earlier versions
}
The Output of this will be as below:
nextTriggerDate ===>>> 2018-07-02 13:30:00 +0000
Request ===>>> Optional(
Calendar Year: 2018
Month: 7
Day: 2
Hour: 19
Minute: 0
Second: 0, repeats: YES>)
You can set weekday and time in DateComponents you can receive notification for every monday at 7:00 PM and also set Repeat = "true"
func setupNotificationReminder() {
let title:String = "Your reminder text goes here"
var calendarComponents = DateComponents()
calendarComponents.weekday = 2
calendarComponents.hour = 19
calendarComponents.second = 0
calendarComponents.minute = 0
// create a corresponding local notification
let trigger = UNCalendarNotificationTrigger(dateMatching: calendarComponents, repeats: true)
let content = UNMutableNotificationContent()
content.title = title
content.body = "body"
content.sound = UNNotificationSound.default()
content.categoryIdentifier = "YourApp"
let request = UNNotificationRequest(identifier: "NotificationAtGivenTime", content: content, trigger: trigger)
UNUserNotificationCenter.current().add(request) {(error) in
if let error = error {
print("Uh oh! We had an error: \(error)")
}
}
}
Another overload of trigger required TimeInterval
So you can get
let timeInterval = dateOfNotification.timeIntervalSinceNow
Now
let trigger = UNTimeIntervalNotificationTrigger(timeInterval: timeInterval, repeats: true)
You can create date as
if let date = Calendar.current.date(byAdding: .day, value: 7, to: self) {
let date1 = Calendar.current.date(bySettingHour: hours, minute: minutes, second: 00, of: date)
}
If you want specific day then refer https://stackoverflow.com/a/49561764/4601900

Resources