Reputation: 2154
I'm working on an Alarm app for iOS which uses UILocalNotifications. So far so good, until somebody came up with the idea of showing a route from where the user is to where he wants to go.
For this I thought I could maybe get the last fired UILocalNotification ( All of them have repeatInterval set as weekly or daily).
Here is where the whole trouble comes in, since the fireDate is the first time I scheduled them: This is my scenario:
UILocalNotification* ln = [[UILocalNotification alloc] init];
ln.fireDate = date; // For instance 07/19/2014 10:00:00 (Saturday)
ln.repeatInterval = NSDayCalendarUnit;
[[UIApplication sharedApplication] scheduleLocalNotification:ln];
UILocalNotification* ln = [[UILocalNotification alloc] init];
ln.fireDate = date; // For instance 07/17/2014 11:00:00 (Thursday)
ln.repeatInterval = NSWeekCalendarUnit;
[[UIApplication sharedApplication] scheduleLocalNotification:ln];
Let picture this:
Next Thursday (07/24/2014 11:00:01) I want to know that the last fired UILocalNotification was the second one that only repeats on Thursdays and the next day I want the first one since it repeats daily.
I've tried to sort by date all LocalNotifications with no success.
Has anyone ever faced a situation akin to it before?
Regards
Upvotes: 2
Views: 1115
Reputation: 2154
Based on @Sid's answer and some code snippets from SO I could come up with this solution which calculates the last fired date for all local notifications without writing it to a file or even to a database. ( Although writing it somewhere isn't a bad idea )
Header
#import <UIKit/UIKit.h>
@interface UILocalNotification (LastFireDate)
- (NSDate *)lastFireDateBeforeDate:(NSDate *)afterDate;
@end
Implementation
#import "UILocalNotification+LastFireDate.h"
@implementation UILocalNotification (LastFireDate)
- (NSDate *)lastFireDateBeforeDate:(NSDate *)afterDate
{
// Check if fire date is in the future:
if ([afterDate compare:self.fireDate] == NSOrderedAscending)
return [NSDate dateWithTimeIntervalSince1970:0];
// 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 *lastFireDate = [cal dateByAddingComponents:difference
toDate:self.fireDate
options:0];
// If necessary, subtract one interval:
if ([lastFireDate compare:afterDate] == NSOrderedDescending) {
switch (self.repeatInterval) {
case NSWeekCalendarUnit:
difference.week--;
break;
case NSDayCalendarUnit:
difference.day--;
break;
case NSHourCalendarUnit:
difference.hour--;
break;
default:
break;
}
lastFireDate = [cal dateByAddingComponents:difference
toDate:self.fireDate
options:0];
}
return lastFireDate;
}
@end
Usage
NSDate* date = [NSDate date];
NSArray* arrayNotifications = [[UIApplication sharedApplication] scheduledLocalNotifications];
if([arrayNotifications count])
{
NSArray *sorted = [arrayNotifications sortedArrayUsingComparator:^NSComparisonResult(UILocalNotification *obj1, UILocalNotification *obj2) {
NSDate *next1 = [obj1 lastFireDateBeforeDate:date];
NSDate *next2 = [obj2 lastFireDateBeforeDate:date];
return [next1 compare:next2];
}];
UILocalNotification* lastLocalNotification = [sorted lastObject];
NSLog(@"%s %@",__PRETTY_FUNCTION__,[lastLocalNotification lastFireDateBeforeDate:date]);
}
Hope it helps someone who is facing the same issue
Cheers
Upvotes: 2
Reputation: 1144
iOS will discard a local notification after it fires even if it is scheduled to repeat itself via the repeatInterval
property.
[UIApplication sharedApplication].scheduledLocalNotifications
actually returns all notifications that are scheduled to be fired in the future. So their fireDate
will be set to a date in the future.
After further investigation, it seems that the fireDate
is always set to the original value specified when the notification was created. However, the next fire date, a calculated value, will be in the future. To see this value simply run po yourNotificationObj
in the debugger and you will see the following type of output, which includes the next fire date:
{fire date = Saturday, July 26, 2014 at 1:42:50 PM Eastern Daylight Time, time zone = (null), repeat interval = NSMinuteCalendarUnit, repeat count = UILocalNotificationInfiniteRepeatCount, next fire date = Saturday, July 26, 2014 at 1:43:50 PM Eastern Daylight Time, user info = (null)}
How do you calculate the next fire date? Please see the following code taken from How to grab the NEXT fire date from a UILocalNotification object:
NSCalendar *calendar = localNotif.repeatCalendar;
if (!calendar) {
calendar = [NSCalendar currentCalendar];
}
NSDateComponents *components = [[[NSDateComponents alloc] init] autorelease];
// If you use some other repeat interval you would have to change the code accordingly.
// If you were to use NSMonthCalendarUnit you would have
// to use `components.month = 1' instead
components.day = 1;
NSDate *nextFireDate = [calendar dateByAddingComponents:components toDate:localnotif.fireDate options:0];
If you want to remember the last fired local notification then you must build that logic into your app and save the required information. For example, you could do the following:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
UILocalNotification *localNotification = [launchOptions objectForKey:UIApplicationLaunchOptionsLocalNotificationKey];
if (localNotification) {
[self saveLocalNotification:localNotification];
}
return YES;
}
- (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification
{
[self saveLocalNotification:notification];
}
- (void)saveLocalNotification:(UILocalNotification *)notification
{
// save information about the last fired local notification on disk
}
- (UILocalNotification *)lastFiredLocalNotification
{
// read the information stored on disk by the saveLocalNotification: method
// and recreate the notification. I'm just saying recreate the notification
// because I don't know what exactly you're trying to do. You
// can return anything you want here
}
Using the above setup, you can call the lastFiredLocalNotification
method whenever you need it.
Upvotes: 5
Reputation: 66234
iOS discards local notifications after they're fired. You're responsible for maintaining this information in some other way if you need the information later.
If you want, you can inspect [UIApplication sharedApplication].scheduledLocalNotifications.firstObject
to see the next one that's scheduled, then use that information to determine from your own data model which was before it.
Upvotes: 2