iOS Notification Trigger: Every Two Months & Every Three Months - ios

I'm trying to create notifications that repeat every two months or every three months, depending on the user's selection.
I can successfully create one that sends a notification two/three months after the user makes their initial choice, but the 'repeats:' part is stuck on that day, so it will just repeat once a year at whatever two/three months after their initial selection was.
How can I create a notification that repeats every two/three months? Is there a way to repeat the dateRequest() function call each time the notification is triggered? That way, I could continually get a notification every two/three months because the call would be refreshed.
Here's my code to create the 'every two months' notification. The three months code is essentially the same.
var components = DateComponents()
//if it's January - October, send notification two months after the current month
if Date().currentMonth()! < 11 {
components.month = Date().currentMonthPlusTwo()
//if it's November, send notification in January
} else if Date().currentMonth()! == 11 {
components.month = 1
//if it's December, send notification in February
} else if Date().currentMonth()! == 12 {
components.month = 2
}
components.day = Date().dayOfMonth()
components.hour = 14
components.minute = 30 //every two months at 2:30pm
NotificationService.shared.dateRequest(with: components, contactName: storedContacts[key].key, identifier: storedContacts[key].value[10])
Any feedback is appreciated. Thank you.

Related

Swift: Mute notifications for current day

in my app I send a daily notification to remind the user to visit the app.
This notification is locally delivered every day at 1pm.
func scheduleNotifications() -> Void {
for notification in notifications {
let content = UNMutableNotificationContent()
content.title = notification.title
let todaysDate = Date()
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "dd"
let currentDay = dateFormatter.string(from: todaysDate)
let currentDayInt = Int(currentDay) ?? 0
var datComp = DateComponents()
datComp.hour = 13
datComp.minute = 00
datComp.day = currentDayInt + 1
let trigger = UNCalendarNotificationTrigger(dateMatching: datComp, repeats: true)
let request = UNNotificationRequest(identifier: notification.id, content: content, trigger: trigger)
UNUserNotificationCenter.current().add(request) { error in
guard error == nil else { return }
print("Scheduling notification with id: \(notification.id) on Day \(datComp.day ?? 00) at \(datComp.hour ?? 00) - \(datComp.minute ?? 00)")
}
}
}
As you can see, I added the "current day + 1" lines because if the user opens the app before 1pm, there is no need to deliver the notification on this day.
So every time the user opens the app, I use UNUserNotificationCenter.current().removeAllPendingNotificationRequests() to remove and reschedule the notification for the next day (by recalling the function above).
My issue:
The notification should repeat every day, which it does, as long as the user opens the app.
But if the user does not open the app on one day, there will be no notification on the following days.
Is there a way to mute notifications for the current day so that I don't have to use this "current day + 1"-thing? Or does anyone have a better idea?
Thank you guys.
I think you misunderstood how repeating notifications and your datComp works here.
For example (let's use today's date: May 27)
datComp.hour = 13
datComp.minute = 00
datComp.day = currentDayInt + 1 // in our example it's 28
let trigger = UNCalendarNotificationTrigger(dateMatching: datComp, repeats: true)
means that your notification will get triggered every month on 28th, all parameters your trigger knows is hour, minute, day and by repeating it, will be triggered on every 28th at 13:00.
So the way your app works now is that you set up monthly notification starting from tomorrow, when you open the app you remove that monthly notification and reschedule it for day later. By opening every day it gives you impression that its daily notification but it's not, it's monthly. That's why if you don't open the app nothing shows up next the day, it will show up next month.
You can check my similar explanation here: (top answer there, maybe it is better worded and easier to understand)
Removing scheduled local notification
and my solution for similar problem i had here:
How to set up daily local notification for tasks but don't show it when user completes the task before

Using a UNCalendarNotificationTrigger with dateMatching produces a trigger date 5 hours after the intended time

I'm trying to schedule an iOS notification at the same hour and minute every day.
First I define a DateComponents:
var components = DateComponents()
components.hour = 1
components.minute = 10
components.second = 0
Then use this to make the trigger:
let trigger = UNCalendarNotificationTrigger(dateMatching: components, repeats: true)
Printing the components yields the expected result:
hour: 1 minute: 10 second: 0 isLeapMonth: false
But printing the trigger's next trigger date always shows a time 5 hours later than what it should:
Optional(2017-07-18 06:10:00 +0000)
Any idea what's going on here? I've tried setting the time zone on the components and it doesn't have any effect.
Edit: It looks like the notifications are actually firing at the correct time (I had a different issue which had broken them). I still can't explain the behavior of nextFireDate though.

How to set an alarm for 2 week days with UserNotifications API

I am trying to simulate the stock alarm app usage with the UserNotifications API but I am having hard time doing it.
For a single specific weekday (monday in this case) its all good.
NSDateComponents *components = [NSDateComponents new];
components.hour = 13;
components.minute = 0;
components.second = 0;
components.weekday = 2;
According to Apple: "The weekday units are the numbers 1 through N (where for the Gregorian calendar N=7 and 1 is Sunday)."
But if I want both monday and tuesday (should be 1 + 2?, which points to wednesday) I can't get it working.
This walkthrough also have detailed information. "To create a trigger that repeats at a certain interval use the correct set of date components. For example, to have the notification repeat daily at the same time we need just the hour, minutes and seconds:"

Repeating Local Notifications every Week with Swift

I have an app using local notifications there is a total of 64 notifications, which is the limit of local notifications. I need to repeat each notification every week. I know that to set the repeat interval you use:
alarm.repeatInterval = NSCalendarUnit
I have tried using the .WeekOfYear and .WeekOfMonth. Do they repeat the notification every year or month? And I do not know the calendar unit for weekly. Which one can I use to repeat weekly?
Edit:
This is the code I am using to set the notifications.
let notifyAlarm = UILocalNotification()
let component = NSDateComponents()
component.hour = NSUserDefaults.standardUserDefaults().integerForKey("Hour1")
component.minute = NSUserDefaults.standardUserDefaults().integerForKey("Minute1")
component.weekday = 1
notifyAlarm.fireDate = calendar.dateFromComponents(component)
notifyAlarm.timeZone = NSTimeZone.defaultTimeZone()
notifyAlarm.alertBody = NSUserDefaults.standardUserDefaults().stringForKey("Message1")
notifyAlarm.repeatInterval = NSCalendarUnit.WeekdayOrdinal
notifyAlarm.soundName = NSUserDefaults.standardUserDefaults().stringForKey("Sound1")
app.scheduleLocalNotification(notifyAlarm)
I am setting 64 notifications like that at once. But with different dates.
If you want the notification to fire for first time after a week you need to change the fire date.
I use TimeIntervalSinceNow for this, which is in seconds, so 1 week would be around 604000 seconds.
You can use _ to separate numbers for legibility.
alarm.fireDate = NSDate(timeIntervalSinceNow: 604_000)
Maybe a bit clunky but I think its the easiest for those type of notifications. I do something like this to make it easier.
struct NotificationFireDate {
static let nextDay: NSTimeInterval = 85_000
static let nextWeek: NSTimeInterval = 604_000
}
and than use it like so
alarm.fireDate = NSDate(timeIntervalSinceNow: NotificationFireDate.nextWeek)
Repeat interval should be weekOfYear
alarm.repeatInterval = NSCalendarUnit.WeekOfYear
The first repeating notification should fire 1 week after the first (fireDate) notification fired.
For a full list have a look at this (thanks madmik3)
https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Classes/NSCalendar_Class/#//apple_ref/c/tdef/NSCalendarUnit

Why UILocalNotifications does not repeat?

I want to run UILocalNotifications and repeat it every 2 minutes. For this I do:
let reminderNote: UILocalNotification = UILocalNotification()
reminderNote.fireDate = NSDate(timeIntervalSinceNow: 60 * 2)
reminderNote.repeatInterval = NSCalendarUnit.Hour
reminderNote.alertBody = "some text"
reminderNote.alertAction = "View"
UIApplication.sharedApplication().scheduleLocalNotification(reminderNote)
It runs it just one time, later it does not.
I think it's because of this line:
reminderNote.repeatInterval = NSCalendarUnit.Hour
How can I repeat my notifications every 1.5 or 2 hours?
Directly you can not.
Unfortunately repeatInterval can Only be set as TimeUnit Such as Hour, Minute, Second etc.
Eg: Lets say if you want to repeat notification in each 2 minutes, You will need to create 30 notifications that repeats hourly.
firedate sets the time that the notification fires the first time, and repeatInterval is the interval between between repetitions of the notification.
Unfortunately, you can only schedule notifications to repeat at exact intervals defined by NSCalendar constants: e.g., every minute, every hour, every day, every month, but not at multiples of those intervals.
Luckily, to get a notification every 2 minutes, you can just schedule 29 notifications: one right now, one 2 minutes from now, and later one 2 minutes from previous one - up to your 29 notification schedules, and have all repeat every hour. Like so:
So the code in the question schedules a notification to fire every 2 minutes (60 * 2 seconds) from now, and then repeat every hour.
UILocalNotification *reminderNote = [[UILocalNotification alloc]init];
reminderNote.fireDate = [NSDate dateWithTimeIntervalSinceNow:60 * 2];
reminderNote.repeatInterval = NSHourCalendarUnit;
reminderNote.alertBody = #"some text";
reminderNote.alertAction = #"View";
reminderNote.soundName = #"sound.aif";
[[UIApplication sharedApplication] scheduleLocalNotification:reminderNote];
reminderNote.fireDate = [NSDate dateWithTimeIntervalSinceNow:60 * 60];
[[UIApplication sharedApplication] scheduleLocalNotification:reminderNote];
For 2 hours, you set your notification for now, after 2 hours from now and 2 hours from the previous one up to 11 notification (12*2 hours) = 24 - 2 hour (because 1st one will be on the day change) = 22/2 = 11 notifications will be required to set on the repeat interval of day by NSDayCalendarUnit.

Resources