Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Detect next UILocalNotification that will fire

Is there a way to find the NSDate for the next local notification that will fire?

For example, I've set up three local notifications:

Notification #1: Set to fire yesterday at 3:00 PM with repeat interval of daily.

Notification #2: Set to fire today at 5:00 PM with repeat interval of daily.

Notification #3: Set to fire tomorrow at 6:00 PM with repeat interval of daily.

Given that is is currently 4:00 PM, the next local notification that will fire is notification #2.

How can I retrieve this local notification and get its date?

I know that I can retrieve these local notifications in an array, but how do I get the next one that will fire based on today's date?

like image 373
waylonion Avatar asked Dec 20 '22 19:12

waylonion


1 Answers

The main goal for your task is to determine the "next fire date" after a given date for each notification. The NSLog() output of a UILocalNotification shows this next fire date, but unfortunately it seems not to be available as a (public) property.

I have taken the code from https://stackoverflow.com/a/18730449/1187415 (with small improvements) and rewritten that as a category method for UILocalNotification. (This is not perfect. It does not cover the case that a time zone has been assigned to the notification.)

@interface UILocalNotification (MyNextFireDate)
- (NSDate *)myNextFireDateAfterDate:(NSDate *)afterDate;
@end

@implementation UILocalNotification (MyNextFireDate)
- (NSDate *)myNextFireDateAfterDate:(NSDate *)afterDate
{
    // Check if fire date is in the future:
    if ([self.fireDate compare:afterDate] == NSOrderedDescending)
        return self.fireDate;

    // The notification can have its own calendar, but the default is the current calendar:
    NSCalendar *cal = self.repeatCalendar;
    if (cal == nil)
        cal = [NSCalendar currentCalendar];

    // Number of repeat intervals between fire date and the reference date:
    NSDateComponents *difference = [cal components:self.repeatInterval
                                               fromDate:self.fireDate
                                                 toDate:afterDate
                                                options:0];

    // Add this number of repeat intervals to the initial fire date:
    NSDate *nextFireDate = [cal dateByAddingComponents:difference
                                                     toDate:self.fireDate
                                                    options:0];

    // If necessary, add one more:
    if ([nextFireDate compare:afterDate] == NSOrderedAscending) {
        switch (self.repeatInterval) {
            case NSDayCalendarUnit:
                difference.day++;
                break;
            case NSHourCalendarUnit:
                difference.hour++;
                break;
            // ... add cases for other repeat intervals ...
            default:
                break;
        }
        nextFireDate = [cal dateByAddingComponents:difference
                                            toDate:self.fireDate
                                           options:0];
    }
    return nextFireDate;
}
@end

Using that, you can sort an array of local notifications according to the next fire date:

NSArray *notifications = @[notif1, notif2, notif3];

NSDate *now = [NSDate date];
NSArray *sorted = [notifications sortedArrayUsingComparator:^NSComparisonResult(UILocalNotification *obj1, UILocalNotification *obj2) {
    NSDate *next1 = [obj1 myNextFireDateAfterDate:now];
    NSDate *next2 = [obj2 myNextFireDateAfterDate:now];
    return [next1 compare:next2];
}];

Now sorted[0] will be the next notification that fires.

like image 114
Martin R Avatar answered Jan 13 '23 18:01

Martin R