Everyone has likely since moved on, but I'd like to share my solution to this problem. (Sorry about the long variables names...)
The idea is simple: always keep the fireDate in the future.
-every time didFinishLaunchingWithOptions or didReceiveLocalNotification is invoked, simply cancel your current notification and reschedule a new one with a fireDate one interval unit in the future
-When your app launches iterate through all scheduled notifications, if the fireDate is not in the future you know that it was ignored
In my case, the notifications have a weekly repeat interval. I first reschedule any acknowledged notifications in didFinishLaunchingWithOptions:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
UILocalNotification* localNotif = [launchOptions objectForKey:UIApplicationLaunchOptionsLocalNotificationKey];
if (localNotif != nil)
{
[NotificationsHelper rescheduleNotification:localNotif];
}
}
And also in didReceiveLocalNotification:
- (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *) notification
{
[NotificationsHelper rescheduleNotification:notification];
}
At App Launch I check all notifications for any with a fireDate in the past:
- (void)applicationDidBecomeActive:(UIApplication *)application
{
[self checkLocalNotifications:application];
}
Code for my "checkLocalNotifications" function:
- (void) checkLocalNotifications:(UIApplication *) application
{
UIApplication* app = [UIApplication sharedApplication];
NSArray* eventArray = [app scheduledLocalNotifications];
for (int i = 0; i < [eventArray count]; i++)
{
UILocalNotification* notification = [eventArray objectAtIndex:i];
if ([NotificationsHelper wasWeeklyRepeatingNotificationIgnored:notification])
{
[NotificationsHelper rescheduleNotification:notification];
NSLog(@"NotificationWasIgnored: %@ %@",notification.alertAction, notification.alertBody );
}
}
}
Code for my "wasWeeklyRepeatingNotificationIgnored" function:
+ (BOOL) wasWeeklyRepeatingNotificationIgnored:(UILocalNotification*) the_notification
{
BOOL result;
NSDate* now = [NSDate date];
// FireDate is earlier than now
if ([the_notification.fireDate compare:now] == NSOrderedAscending)
{
result = TRUE;
}
else
{
result = FALSE;
}
return result;
}
Code for my "rescheduleNotification" function:
+ (void) rescheduleNotification:(UILocalNotification*) the_notification
{
UILocalNotification* new_notification = [[UILocalNotification alloc] init];
NSMutableDictionary* userinfo = [[NSMutableDictionary alloc] init];
[new_notification setUserInfo:userinfo];
[new_notification setRepeatInterval:the_notification.repeatInterval];
[new_notification setSoundName:UILocalNotificationDefaultSoundName];
[new_notification setTimeZone:[NSTimeZone defaultTimeZone]];
[new_notification setAlertAction:the_notification.alertAction];
[new_notification setAlertBody:the_notification.alertBody];
[new_notification setRepeatCalendar:[NSCalendar currentCalendar]];
[new_notification setApplicationIconBadgeNumber:the_notification.applicationIconBadgeNumber];
NSCalendar* gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSDateComponents* weekdayComponents = [gregorian components:NSWeekdayCalendarUnit
fromDate:the_notification.fireDate];
NSInteger weekday = [weekdayComponents weekday];
NSDate* next_week = [self addDay:weekday toHourMinute:the_notification.fireDate];
[new_notification setFireDate:next_week];
[[UIApplication sharedApplication] scheduleLocalNotification:new_notification];
[[UIApplication sharedApplication] cancelLocalNotification:the_notification];
}