Is it possible to have a Conditioned `firedate` for UILocalNotification? - iphone

I'm trying to have a conditioned firedate time for my local notifications, however when I tried these two ways it didn't fail but it still didn't work. So, I was wondering if I'm able to do such a thing?
Note: startTime and endTime are times from date pickers.
-(void) TEST {
NSCalendar *calendar = [NSCalendar currentCalendar];
calendar.timeZone = [NSTimeZone timeZoneWithName:#"GMT"];
NSDateComponents *components = [calendar components:NSHourCalendarUnit fromDate:[NSDate date]];
components.hour = 3;
components.minute = (components.minute + 1) % 60;
components.second = 57;
NSDate *fire = [calendar dateFromComponents:components];
UILocalNotification *notif = [[UILocalNotification alloc] init] ;
if (notif == nil)
return;
if (fire < startTime.date) {
notif.fireDate =fire ;
notif.repeatInterval= NSMinuteCalendarUnit ;
notif.alertBody = [NSString stringWithFormat: #"You are missed!"] ;
[[UIApplication sharedApplication] scheduleLocalNotification:notif] ;
}
if (fire > endTime.date) {
notif.fireDate =fire ;
notif.repeatInterval= NSMinuteCalendarUnit ;
notif.alertBody = [NSString stringWithFormat: #"You are missed!"] ;
[[UIApplication sharedApplication] scheduleLocalNotification:notif] ;
}}
OR
-(void) TEST {
NSCalendar *calendar = [NSCalendar currentCalendar];
calendar.timeZone = [NSTimeZone timeZoneWithName:#"GMT"];
NSDateComponents *components = [calendar components:NSHourCalendarUnit fromDate:[NSDate date]];
components.hour = 3;
components.minute = (components.minute + 1) % 60;
components.second = 57;
NSDate *fire = [calendar dateFromComponents:components];
UILocalNotification *notif = [[UILocalNotification alloc] init] ;
if (notif == nil)
return;
if (fire > startTime.date & fire < endTime.date) {
[[UIApplication sharedApplication] cancelAllLocalNotifications] ;
}
else {
notif.fireDate =fire ;
notif.repeatInterval= NSMinuteCalendarUnit ;
notif.alertBody = [NSString stringWithFormat: #"You are missed!"] ;
[[UIApplication sharedApplication] scheduleLocalNotification:notif] ;
}}
Thanks
If not, what would be the easiest way to make such a condition?

use the NSDate Compare: method instead of if(fire > startTime.date)
if([fire compare: startTime.date] == NSOrderedDescending) // if start is later in time than end
{
// do something
}
From the class reference:
If:
The receiver and anotherDate are exactly equal to each other, NSOrderedSame.
The receiver is later in time than anotherDate, NSOrderedDescending.
The receiver is earlier in time than anotherDate, NSOrderedAscending.
so for your condition
if (fire > startTime.date & fire < endTime.date) {
[[UIApplication sharedApplication] cancelAllLocalNotifications] ;
}
you can use
if([fire compare: startTime.date] == NSOrderedDescending && [fire compare: endTime.date]== NSOrderedAescending)
{
[[UIApplication sharedApplication] cancelAllLocalNotifications] ;
}
this will cancel the all local notifications if fire is between the selected start and end date
else {
// Fire the notifications
}
also have a look at the link this is similar to what you need link

what i, will try do do is, when the sleep Time starts,call a method eg: goingToSleep:, you can use
dispatch_later or performSelector:withObject:afterDelay: for that,
in goingToSleep:
NSArray* localNotifications = [[UIApplication sharedApplication]
scheduledLocalNotifications];
for (UILocalNotification *notification in localNotifications)
{
if([fire compare: startTime.date] == NSOrderedDescending &&
[fire compare: endTime.date]== NSOrderedAescending)
{
This is the important part
get all the properties of the notification
create a NSDictionary of those properties
Add the NSDictionary to an array
and save that array into a plist.(Save Array to Plist)
and then Cancel that notification using
[[UIApplication sharedApplication] cancelLocalNotification:notification];
}
}
then after SleepTime is over
, again call a method eg: wakingUp:
then in wakingUp:
read the array of NSDictionary we saved.
again Create UILocalnotifications using those same Properties.
this way, no UILocalNotifications will trigger during sleep time. one issue can be executing those methods, if the Application is not memory.
EDIT To have long Running Appicaions.

Related

Local notifications are not coming on the datetime I want

I'm working with local notification. I got the notifications working. But I'm struggling with setting the correct date.
Let me first sketch the situation. I am making a festival app. This festival is on the 28-29-30 JUNE. Every artist object has an art_day. This can be 1 - 2 or 3.
1 --> 28 JUNE
2 --> 29 JUNE
3 --> 30 JUNE
I want a local notification 15 min before the start time of the artist. So this is how I'm making my fireDate of the notification.
-(NSDate *)getDateForArtist:(Artists *)artist{
int day = [artist.art_day intValue];
int timeStart = [artist.art_timestart intValue];
NSString *timeStart2 = [self getTimeStamp:artist.art_timestart];
int hours = [[timeStart2 substringWithRange:NSMakeRange(0,2)]intValue];
int minutes = [[timeStart2 substringWithRange:NSMakeRange(2,2)]intValue];
//in my db timeStart looks like 1530 --> 15h30 (I know bad db structure!!!)
int day2;
if(day == 1){
NSLog(#"day is 28");
day2 = 28;
}else if (day == 2){
NSLog(#"day is 29");
day2 = 29;
}else{
NSLog(#"day is 30");
day2 = 30;
}
NSDateComponents *comps = [[NSDateComponents alloc] init];
NSTimeZone *timeZone = [NSTimeZone timeZoneWithName:#"GMT"];
[comps setTimeZone:timeZone];
[comps setDay:day2];
[comps setMonth:06];
[comps setYear:2013];
[comps setHour:hours];
[comps setMinute:minutes];
NSCalendar *gregorian = [[NSCalendar alloc]
initWithCalendarIdentifier:NSGregorianCalendar];
NSDate *date = [gregorian dateFromComponents:comps];
NSLog(#"date is %#",date);
NSDateComponents *offsetComponents = [[NSDateComponents alloc] init];
[offsetComponents setMinute:-15];
NSDate *date2 = [gregorian dateByAddingComponents:offsetComponents toDate:date options:0];
NSLog(#"date -15 min %#", date2);
return date2;
}
This is how I create my notification
UIApplication* app = [UIApplication sharedApplication];
UILocalNotification* notifyAlarm = [[UILocalNotification alloc]
init];
if (notifyAlarm)
{
NSDate *datePush = [self getDateForArtist:artist];
NSLog(#"artist plays on: %# on hour %#",artist.art_day,artist.art_timestart);
NSLog(#"Push notification should send on: %#",datePush);
notifyAlarm.fireDate = datePush;
NSDictionary *dicNotification = [[NSDictionary alloc]initWithObjectsAndKeys:artist.art_id,#"pushKey", nil];
notifyAlarm.userInfo = dicNotification;
notifyAlarm.timeZone = [NSTimeZone defaultTimeZone];
notifyAlarm.repeatInterval = 0;
notifyAlarm.soundName = #"Glass.aiff";
notifyAlarm.alertBody = [NSString stringWithFormat:#"%# starts in 15 minutes",artist.art_name];
[app scheduleLocalNotification:notifyAlarm];
NSLog(#"Added");
}
But for some reason I don't get any push notification. Or I think that the date is not correct.
This is what I get from my logs
2013-06-29 15:37:17.801 genkonstage[14120:907] artist plays on day: 2 on hour 2020
2013-06-29 15:37:17.803 genkonstage[14120:907] Push notification should send on: 2013-06-29 20:05:00 +0000
Can anybody help me with this?

Schedule local Notification after app was closed for 7 days

It was quite a bit hard to enable local notifications for my application.
And yeah, I set up my project with a local notification witch I want to schedule after the app had been closed for one week. For example if the user opens the app on saturday 8th, the local notification should appear on the next saturday the 15th, but the time should changed. For example he/she closes the app at 8pm and I don't want to disturb them at 8pm next week so I want to display every notification at 6pm or something like that.
Now you know my problem and here is my code I'm using:
- (void)applicationDidEnterBackground:(UIApplication *)application
{
[[UIApplication sharedApplication] cancelAllLocalNotifications];
NSCalendar *calendar = [NSCalendar autoupdatingCurrentCalendar] ;
NSDateComponents *componentsForReferenceDate = [[NSDateComponents alloc] init];
//set day (saturday)
[componentsForReferenceDate setDay:26] ;
[componentsForReferenceDate setMonth:1] ;
[componentsForReferenceDate setYear:2013] ;
[componentsForReferenceDate setHour: 17] ;
[componentsForReferenceDate setMinute:30] ;
[componentsForReferenceDate setSecond:00] ;
NSDate *fireDateOfNotification = [calendar dateFromComponents: componentsForReferenceDate];
// Create the notification
UILocalNotification *notification = [[UILocalNotification alloc] init] ;
notification.fireDate = fireDateOfNotification ;
notification.timeZone = [NSTimeZone localTimeZone] ;
notification.alertBody = [NSString stringWithFormat: #"Du wirst vermisst! \nDeine App braucht dich, schreibe sie zu Ende!"] ;
notification.alertAction = #"Zurückkehren";
notification.userInfo= [NSDictionary dictionaryWithObject:[NSString stringWithFormat:#"Some information"] forKey:#"information"];
notification.repeatInterval= NSWeekCalendarUnit ;
notification.soundName = #"Appnotifisound.wav";
notification.applicationIconBadgeNumber = 1;
[[UIApplication sharedApplication] scheduleLocalNotification:notification] ;
}
I know that there have to be more methods for deleting the badge and the didrecievenotification, but I let them out because there are not important for this.
With this code I managed to schedule the notification on every saturday at 5:30pm (Germany). But I wanted to schedule it only once, when the app had been closed for exactly one week. Is that somehow possible? I would be glad if someone could correct my code or give me a solution for this.
Best regards and thank you for reading this long post,
Noah
You should unschedule previous notification.
for (UILocalNotification *lNotification in [[UIApplication sharedApplication] scheduledLocalNotifications])
{
if ([[lNotification.userInfo valueForKey:#"information"] isEqualToString:#"Some information"])
{
[[UIApplication sharedApplication]cancelLocalNotification:lNotification];
break;
}
}
Set fire date by below way:
NSCalendar *calendar = [NSCalendar currentCalendar];
NSDateComponents *componentsForReferenceDate = [calendar components:(NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit)
fromDate:[NSDate date]];
[componentsForReferenceDate setHour: 17] ;
[componentsForReferenceDate setMinute:30] ;
[componentsForReferenceDate setSecond:00] ;
NSDate *tempDate = [calendar dateFromComponents: componentsForReferenceDate];
[componentsForReferenceDate release];
NSDateComponents *comps = [[NSDateComponents alloc]init];
[comps setDay:7];
NSDate *fireDateOfNotification = [calendar dateByAddingComponents:comps
toDate:tempDate options:0]
[comps release];
The notification.repeatInterval = NSWeekCalendarUnit is causing this. use:
notification.repeatInterval = 0;
This prevent repeating (source).
Here is the Swift 2.0 adaptation
Unscheduling the current notification
for notifMe:AnyObject in UIApplication.sharedApplication().scheduledLocalNotifications!{
let title = notifMe.userInfo["information"] as? String
if title == "some information"{
UIApplication.sharedApplication().cancelLocalNotification(notifMe as! UILocalNotification)
}
}
Setting the date for the notification
let date = NSDate()
let calendar = NSCalendar.currentCalendar()
let components = calendar.components(NSCalendarUnit.Year.union(NSCalendarUnit.Month).union(NSCalendarUnit.Day),fromDate: date)
components.hour = 17
components.minute = 30
components.second = 00
let tempDate = calendar.dateFromComponents(components)!
let comps = NSDateComponents()
comps.day = 7
let fireDateOfNotification = calendar.dateByAddingComponents(comps, toDate: tempDate, options:[])

Fire Date issue in local notification

I have a view controller which contains a field for user to enter date value.In contrast I have a field called "Remind Before Days" for the user to select when the notification should fire.If the remind before day is same day,then notification is set to fire on the date,but when the remind day is before 1 day,then notification should fire before one day the date set(specified).For this I have written a method called -(void)setNotification and here is the implementation code:
- (void)setNotification
{
//Set notification after confirmation of saved data
Class cls = NSClassFromString(#"UILocalNotification");
UILocalNotification *notif = [[cls alloc] init];
if (cls != nil)
{
textField = [self.fields objectAtIndex:3];
if (textField.text == #"Same Day")
{
notif.fireDate = [datePicker date];
notif.timeZone = [NSTimeZone defaultTimeZone];
}
else if(textField.text == #"1 Day")
{
NSDate *now = [datePicker date];
// set up date components
NSDateComponents *components = [[NSCalendar currentCalendar] components:NSDayCalendarUnit | NSMonthCalendarUnit | NSYearCalendarUnit fromDate:now];
[components setDay:-1];
// create a calendar to form date
NSCalendar *gregorian = [[[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar] autorelease];
NSDate *newDate2 = [gregorian dateByAddingComponents:components toDate:now options:0];
notif.fireDate = newDate2;
notif.timeZone = [NSTimeZone defaultTimeZone];
}
notif.timeZone = [NSTimeZone defaultTimeZone];
notif.alertBody = textView.text;
notif.alertAction = #"View";
notif.soundName = #"lazy_afternoon.mp3";
notif.applicationIconBadgeNumber = 1;
textField = [self.fields objectAtIndex:1];
NSDictionary *userDict = [NSDictionary dictionaryWithObject:self.textField.text forKey:kReminder];
notif.userInfo = userDict;
[[UIApplication sharedApplication] scheduleLocalNotification:notif];
[notif release];
}
}
Now as we are all aware that when the notification gets fired,the user clicks view.Then we show an alert,the implementation code is written in appDelegate.Here it is:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// For The Purpose Of Notification.
Class cls = NSClassFromString(#"UILocalNotification");
if (cls)
{
UILocalNotification *notification = [launchOptions objectForKey:
UIApplicationLaunchOptionsLocalNotificationKey];
if (notification)
{
NSString *reminderText = [notification.userInfo objectForKey:kReminder];
[self.viewController showReminder:reminderText];
}
}
application.applicationIconBadgeNumber = 0;
}
Now after local notification is received,we do the following i.e.:
- (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification
{
application.applicationIconBadgeNumber = 0;
NSString *reminderText = [notification.userInfo objectForKey:kReminder];
[self.viewController showReminder:reminderText];
}
Now I have set the -(void)setNotification action to right navigation right bar button item titled "Save" as follows:
-(IBAction)save:(id)sender
{
[self setNotification];
}
When I don't specify any condition for fire date i.e. simply assign as :
notif.fireDate = [datePicker date]; everything's fine with notification(no issues).
But when I do as the above i.e. condition for fire date,then the notification is not getting fired.Instead the alert is getting fired when I click save.Also when I quit the simulator,I could see some thread problem.I don't understand what's wrong with the code (implementation).I have gone through several links,also the apple documentation of UILocalNotification.Couldn't find out any property or method to set fire Date according to conditions.
I found out a method "repeatTimeInterval" which is relavant and applicable when a notification must be repeated weekly,yearly etc..which doesn't suit the requirement that the "date to be fired is this when the remind days in textField is this"
Can any one please guide me right,
Thanks all in advance :)
I believe if you check this link out you will find out. But from what I have seen the code you have provide is from this site anyway.
http://useyourloaf.com/blog/2010/7/31/adding-local-notifications-with-ios-4.html
I know I arrived a little late, but for me, the error on your code is here:
if (textField.text == #"Same Day")
Because you can't compare NSStrings using the operator ==. I think that if you use isEqualToString:(NSString*) it will work properly. It would be great if you could edit your original post and fix the code, so people looking for info about local notifications won't run into the same problem.

scheduled local notification is not being stored in the scheduledLocalNotification array

I am currently scheduling local notifications to appear once per day at 6PM if a user has not already opened the app that day. If the user has already loaded the application, then I want to cancel the notification for that day and schedule a new one for tomorrow at 6PM. The notification displays properly, however, when I try to iterate of the list of scheduled notifications (this is not the only local notification I have in the application), the [[UIApplication sharedApplication] scheduledLocalNotifications] array is always empty. Below is the code snippet that is giving me trouble:
// See if we need to create a local notification to tell the user that they can receive a daily reward
NSArray *notifications = [[UIApplication sharedApplication] scheduledLocalNotifications]; // <- This is always empty
// Iterate over all the pending notifications
for( int iter = 0; iter < [notifications count]; iter++ )
{
UILocalNotification* localNotification = [notifications objectAtIndex:iter];
if( [[localNotification.userInfo objectForKey:#"source"] isEqualToString:#"dailyReminder"] )
[[UIApplication sharedApplication] cancelLocalNotification:localNotification];
}
NSCalendar* calendar = [[[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar] autorelease];
[calendar setTimeZone:[NSTimeZone localTimeZone]];
NSDateComponents *nowComponents = [calendar components:NSDayCalendarUnit | NSMonthCalendarUnit | NSYearCalendarUnit | NSSecondCalendarUnit | NSMinuteCalendarUnit | NSSecondCalendarUnit fromDate:serverDate];
int hour = [nowComponents hour];
int minute = [nowComponents minute];
int second = [nowComponents second];
int hoursToAdd = 18 - hour;
NSDateComponents *comps = [[[NSDateComponents alloc] init] autorelease];
[comps setDay:1];
[comps setHour:hoursToAdd];
[comps setMinute:-minute];
[comps setSecond:-second];
NSDate *tomorrow6PM = [calendar dateByAddingComponents:comps
toDate:serverDate
options:0];
NSMutableDictionary* userInfo = [NSMutableDictionary dictionary];
[userInfo setObject:#"dailyReminder" forKey:#"source"];
scheduleNotification(tomorrow6PM, NSLocalizedString(#"Come Back!", #"daily reminder notification message"), NSLocalizedString(#"Launch", #"daily reminder notification button text"), [UIApplication sharedApplication].applicationIconBadgeNumber+1, userInfo);
the scheduleNotification function is straightforward and just constructs a local notification:
void scheduleNotification(NSDate* fireIn, NSString* bodyText, NSString* alertText, NSUInteger badgeCount, NSMutableDictionary* userInfo)
{
static int appCount = 0;
appCount += 1;
if(!isLocalNotificationEnabled())
return;
Class localNotificationClass = NSClassFromString(#"UILocalNotification");
UILocalNotification* localNotification = [[localNotificationClass alloc] init];
if(!localNotification)
return;
localNotification.fireDate = fireIn;
localNotification.timeZone = [NSTimeZone systemTimeZone];
localNotification.alertBody = bodyText;
localNotification.alertAction = alertText;
localNotification.soundName = UILocalNotificationDefaultSoundName;
localNotification.applicationIconBadgeNumber = badgeCount;
localNotification.userInfo = userInfo;
[[UIApplication sharedApplication] scheduleLocalNotification:localNotification];
[localNotification release];
}
I don't understand why the array of local notifications is always empty. Like I said before the notifications display at the correct time, so they are getting scheduled. Any help is appreciated.
Having similar issues right now. My guess here is that iOS does not schedule the notifications immediately but only at the end of the current run loop. I am running into these problems when setting the scheduledLocalNotifications property several times in the same run loop and changes don't seem to be updated accordingly. I think I will just keep a copy of the local notifications array myself and only set scheduledLocalNotifications and never read it.
localNotification.fireDate = fireIn;
in this line check wheather "fireIn" is object of NSDate or NSString.
If it's NSString convert it into NSDate object with help of NSDateformatter and then assing it to localNotification fireDate.
I was facing same problem previously and resolved it with above mentioned steps.
if the schedule has invalid fire date, it will not get scheduled and result empty array returned, because there never has a valid one schedule, try to print out your localNotification like below, you may find out the problem.
NSLog(#"Notification--->: %#", localNotification);

Pass value of kCFCalendarUnitWeekday

I want to set an alarm on a particular day. I don't understand how to set the value of kCFCalendarUnitWeekday. Here is my code:
NSDateComponents *components = [[NSDateComponents alloc] init];
UILocalNotification *localNotif = [[UILocalNotification alloc] init];
if (localNotif == nil)
return;
localNotif.fireDate = selected;
localNotif.timeZone = [NSTimeZone defaultTimeZone];
localNotif.repeatCalendar = [NSCalendar currentCalendar];
if (isSun) {
[components setWeekday:1];
[localNotif setRepeatInterval:(NSInteger)components];
}
if (isMon) {
[components setWeekday:2];
[localNotif setRepeatInterval:(NSInteger)components];
}
Thank you.
Ok here is some code to get you in the right direction:
NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSDateComponents *components = [gregorian components:NSWeekdayCalendarUnit|NSYearCalendarUnit|NSDayCalendarUnit|NSHourCalendarUnit|NSMinuteCalendarUnit|NSSecondCalendarUnit fromDate:[NSDate date]];
// this will set the weekday to sunday
[components setWeekday:1];
// this is a new date on sunday
NSDate * newDate = [gregorian dateFromComponents:components];
You still have to find out whether the newDate is in the past, so it won't fire.
You actually have your code ready:
// ... init code ...
// *** this the important date ***
localNotif.fireDate = dateOnASunday;
localNotif.timeZone = [NSTimeZone defaultTimeZone];
localNotif.repeatCalendar = NSWeekCalendarUnit;
... // add body etc. ...
[[UIApplication sharedApplication] scheduleLocalNotification:localNotif];
[localNotif release];
Create a method around this snippet and pass the date with a parameter so you can reuse it. You only have to put in a date which should be the first fire date and it'll repeat every week. You just have to pass in a date on a Sunday or Wednesday.
You set a repeat interval like this:
// repeats notification on a weekly basis
localNotif.repeatCalendar = NSWeekCalendarUnit;
The repeatCalender property is of type NSCalendarUnit which is an enum.