UILocalNotification repeatInterval - objective-c

I have 2 questions.
If I understand local notifications the repeatinterval allows me to have a notification scheduled once and it repeated on the same interval each week or month or day of week. I am trying to get a repeatinterval to fire once on say a Tuesday and each week it will fire again on the same day i.e. Tuesday. This should go on every week without needing to schedule another notification. Is that correct. Is is not happening. I am either doing something wrong in code or I am testing it wrong.
In the simulator I run the app schedule the notificaiton. The notification comes up which I view. Then I quit the app and set the system date to 1 week in the future same day of week but no notification so can I test this notification this way by changing the computers system clock. I do not want to have to wait a week for each test.
Here is the code
- (void) scheduleNotificationWithItem:(NSDate *)date interval:(int)frequency {
UILocalNotification *localNotif = [[UILocalNotification alloc]init];
if (localNotif == nil) {
return;
}
localNotif.fireDate = [date addTimeInterval:frequency];
localNotif.timeZone = [NSTimeZone defaultTimeZone];
localNotif.repeatCalendar = [NSCalendar currentCalendar];
localNotif.repeatInterval = kCFCalendarUnitWeekday;
localNotif.applicationIconBadgeNumber = 1;
localNotif.alertBody = [NSString stringWithFormat:NSLocalizedString(#"%#.",nil),#"Weekly Reminder"];
localNotif.alertAction = NSLocalizedString(#"View Notification Details", nil);
localNotif.soundName = UILocalNotificationDefaultSoundName;
[[UIApplication sharedApplication]scheduleLocalNotification:localNotif];
[localNotif release];
}
Please help this is driving me crazy.
Thanks,
Dean

1) Setting your repeat interval to 'NSWeekCalendarUnit' should do the trick. It repeats on a weekly basis on the same day and time as the original notification.
2) I haven't tested in the simulator but changing the clock on an actual iPhone does fire future alerts.

Related

Restoring Game Lives using UILocalNotification

I am creating a game in Spritekit, and I am trying to set up my game in a way that when a player loses all of their lives they have to wait 30 minutes for one of their lives to be restored so that they can play again. I tried using NSTimer to do this but I figured UINotification will be more effective since I want this timer to run whether or not the app is terminated, in the background, being used or not being used. I'm having problems setting this up though.
I have the following code written thus far, when the user reaches the GameOverScene
-(instancetype)initWithSize:(CGSize)size {
if (GameLives < 5 ) {
alarm = [[UILocalNotification alloc] init];
alarm.fireDate = [NSDate dateWithTimeIntervalSinceNow:thirtyNewMinutes];
alarm.timeZone = [NSTimeZone localTimeZone];
[[UIApplication sharedApplication] scheduleLocalNotification:alarm];
alarm.repeatInterval = NSCalendarUnitHour;
NSLog(#"AlarmFireDate = %#", alarm.fireDate);
}
}
The alarm.firedate shows up correctly in the NSLog when I reach the GameOverScene but when I close down my app and restart it, it shows up as null in my view controllers and never fires. How do I get my app to automatically update the user's lives in the background once the notification is scheduled regardless of whether the user is using the app or not? Should it be run in my app delegate?
Should some type of NSDate comparison like the one below run somewhere?
if ([[NSDate date] compare:allarm.fireDate] == NSOrderedDescending) {
GameLives = GameLives + 1;
NSLog(#"SUCCESS");
NSLog(#"COUNT = %lu", (long)GameLives);
}
else if ([[NSDate date] compare:allarm.fireDate] == NSOrderedAscending){
GameLives = GameLives + 1;
NSLog(#"FAILURE");
NSLog(#"COUNT = %lu", (long)GameLives);
}
else if ([[NSDate date] compare:allarm.fireDate] == NSOrderedSame){
NSLog(#"SAME");
NSLog(#"COUNT = %lu", (long)GameLives);
}
I'd be most grateful to anybody that can offer help.
EDIT: RESPONSE TO THE ANSWERS BELOW
I wrote the following code for the NSTimer and the timer starts when the game reaches the GameOver Scene.
-(void)restoreLives{
thirtyNewMinutes = 60 * 30;
update = [NSDate dateWithTimeIntervalSinceNow:thirtyNewMinutes];
if ([[NSDate date] compare:update] == NSOrderedDescending) {
NSLog(#"date1 is later than date2");
NSLog(#"SUCCESS");
NSLog(#"CurrentDate: %#", [NSDate date]);
// LifeText = #"Restored";
GameLives = GameLives + 1;
NSLog(#"LIVES = %ld", (long)GameLives);
// NSLog(#"Level 2 HighScore, %d", _Level1HighScoreNumber);
} else if ([[NSDate date] compare:update] == NSOrderedAscending) {
NSLog(#"date1 is earlier than date2");
NSLog(#"FAILURE");
NSLog(#"CurrentDate: %#", [NSDate date]);
NSLog(#"LIVES = %ld", (long)GameLives);
// Lives = 5;
// NSLog(#"dates are the same");
}
if (GameLives < 4){
[LifeTimer invalidate];
}
And then I created an NSTimer to run the method.
-(void)CheckTime{
LifeTimer = [NSTimer scheduledTimerWithTimeInterval:0.01 target:self selector:#selector(restoreLives) userInfo:nil repeats:YES];
}
How would I get it to save the target time that you're speaking of?
And, hopefully I'm not overthinking this but from another perspective if I wanted to compare the current NSDate with the [NSDate dateWithTimeIntervalSinceNow:thirtyNewMinutes]; wouldn't I need to save the original date of [NSDate dateWithTimeIntervalSinceNow:thirtyNewMinutes]; when it was originally called so that if the app terminates and the timer runs the code again it compares it to the original time the code was called and doesn't reset the NSDate and compare it to 30 minutes from the time the user restarts the app and the timer begins again.
i.e. 7:15
NSDate comparison to update = [NSDate dateWithTimeIntervalSinceNow:thirtyMinutes];
is called. And timer is set to update lives at 7:45.
7:30 User terminates their app and restarts it at 7:35
When the NSTimer runs again won't it reset the time to be 30 minutes from 7:35 since it's 30 minutes from now? If this is the case how would I go about saving the original date? Please let me know, keep in mind I'm still a beginner with Objective C
A local notification works well if you want to inform the user of something, and can have a payload which you could use to keep track of the information you need, but it's probably not the best solution for you to do your timing work. If the user disables notifications for your app, it would break your functionality.
Instead, when it comes to keeping track of events based on a time, it's best to rely on date comparisons along with timers.
While your app is open, you should use an NSTimer to trigger what you need to do, which I think you have covered.
When you app goes to the background or terminates you should save the target time in some kind of persistent storage (NSUserDefaults, for example). When you app is relaunched or returns from the background, you should compare against that date and either start up the timer or trigger your code that the timer would fire yourself.
Try this to save/restore the date:
// Save the date with the key "NextFireDate"
[[NSUserDefaults standardUserDefaults] setObject:nextFireDate forKey:#"NextFireDate"];
// This forces the values to be saved by the system, which normally only happens periodically
[NSUserDefaults standardUserDefaults] synchronize];
...
// Retrieve the date with the key "NextFireDate"
NSDate *nextFireDate = [[NSUserDefaults standardUserDefaults] objectForKey:#"NextFireDate"];
You'd call the first whenever you go to the background/terminate (also invalidate your current timer) and the second when you finish launching or return from the background (and start a new timer with the retrieved date). NSUserDefaults is basically just a dictionary (that can accept scalars without having to box them yourself) that persists as long as your app is installed.

UIDatePicker.date bug

I'm having a problem getting the date from UIDatePicker. I know the code of getting the date, but it just keeps on getting the CURRENT date, not the date form the picker.
- (IBAction)buttonPressed:(UIButton *)sender {
NSDateFormatter *formate = [[NSDateFormatter alloc]init];
NSDate *settedDate = self.myPickedDate.date;
[formate setDateFormat: #"dd.MMM.yyyy # HH:mm:ss"];
NSString *dateString = [formate stringFromDate:settedDate];
NSLog(#"datestring: %#", dateString);
}
I set myPicker to 15th May 2015 15:30 and Xcode logs out the current date (if it's 16:19 he will log out 22nd.Apr.2015 16:19, no matter what.
Xcode 5.1.1 on simulator iOS 7.1.2 (haven't tried on real device).
The problem is that in your viewDidLoad you are saying this:
self.myPickedDate = [[UIDatePicker alloc] init];
So, think about that code. What you are doing there is creating a new date picker, completely different from the one in your interface, and substituting it for the one in your interface, to which self.myPickedDate was previously set (because it is an outlet). So from now on, self.myPickedDate refers to a different date picker, one that is not in your interface (it is merely held in memory)! Therefore, nothing you do in the interface, such as setting the date in the date picker you see there, has any effect on self.myPickedDate.
Therefore, to solve the problem, delete that line of code.

Enable/disable a perticular UILocalNotification and set multiple notification once

NOTE: Need to know how to Set a number of alarm or notification in between two given dates regularly?
I have to create an app where,i have to enable/disable multiple UILocalnotification set in a tableview.'
If i choose a date i have to then set time on that perticular date and also need to set the notification before timePlay (5,10,15,20 min prior).
And End date: the date until when the notification plays regularly.
How to set all the notification for a perticular notification ID at once?
How to disable a perticular notification?
ALSO PLEASE TELL ME : CAN HOW CAN I SET UILOCALNOTIFICATION using database?
I have create a database having
Notification ID //unique id of notification
Notification Name //notification title
Time1 //can set five time the notification will show
Time2(optional)
Time3(optional)
Time4(optional)
Time5(optional)
Before timePlay//can show the notification before time of notification 1 to 5 above
Start Date // the date from which the notification start
End Date //the date when the notification stops.
i can set simple notification like this
// UILocalNotification properties:
// alertBody - the message displayed in the notification
// alertAction - if notification is displayed as an alert, this is the label of the action button, if not specified, "Launch" will be used
// soundName - the name of a sound file (AIFF, CAF or WAV) to be played when the notification appears, if not specified, no sound will be played. To use the default sound UILocalNotificationDefaultSoundName can be provided.
// userInfo - you can pass an NSDictionary object with additional data to be used by our app after the notification fires (optional)
// fireDate - an NSDate object specifying the date and time for the local notification to be fired (obligatory)
// timeZone - an NSTimeZone object. If specified, the fireDate is measured against the user's local time zone, if not against universal time
// repeatCalendar - the calendar (NSCalendar) the system should refer to when it reschedules a repeating notification
// repeatInterval - the calendar interval (NSCalendarUnit) at which to reschedule the notification, the default is 0, which means don't repeat
// alertLaunchImage - will be presented when your app is run or summoned from the background
// Create a new local notification
UILocalNotification *notif = [[UILocalNotification alloc] init];
notif.alertBody = #"Wake up! Its tuition time!";
notif.fireDate = [NSDate dateWithTimeIntervalSinceNow:60]; // 60 seconds
notif.soundName = UILocalNotificationDefaultSoundName;
notif.applicationIconBadgeNumber += 1;
Try scheduling which will enable the notification and use cancel which will be disable the notification:-
-(void)enableNotification
{
[self cancelAlarm]; //clear any previous alarms
UILocalNotification *alarm = [[UILocalNotification alloc] init];
alarm.alertBody = #"alert msg";
alarm.fireDate = [NSDate dateWithTimeInterval:alarmDuration sinceDate:startTime];
alarm.soundName = UILocalNotificationDefaultSoundName;
NSDictionary *userInfo = [NSDictionary dictionaryWithObject:self.name forKey:kTimerNameKey];
alarm.userInfo = userInfo;
[[UIApplication sharedApplication] scheduleLocalNotification:alarm];
}
-(void)disableNotification{
for (UILocalNotification *notification in [[[UIApplication sharedApplication] scheduledLocalNotifications] copy]){
NSDictionary *userInfo = notification.userInfo;
if ([self.name isEqualToString:[userInfo objectForKey:kTimerNameKey]]){
[[UIApplication sharedApplication] cancelLocalNotification:notification];
}
}
at time of notification schedule give a unique notification key in notification's userinfo and to cancel notification you can use below code as where
UIApplication *app = [UIApplication sharedApplication];
NSArray *eventArray = [app scheduledLocalNotifications];
for (int i=0; i<[eventArray count]; i++)
{
UILocalNotification* oneEvent = [eventArray objectAtIndex:i];
NSDictionary *userInfoCurrent = oneEvent.userInfo;
NSString *uid=[NSString stringWithFormat:#"%#",[userInfoCurrent valueForKey:#"uid"]];
if ([uid isEqualToString:uidtodelete])
{
//Cancelling local notification
[app cancelLocalNotification:oneEvent];
break;
}
}

Adding historical events to iOS7 calendar

I just ran into an issue that took me a while to solve and hadn't seen it mentioned on SO, so here it is. I was just trying to programmatically add events to my calendar that are over 1 month old and on iOS7 (not iOS6) these events would not show up in a calendar, and neither were they available when I did a (programatic) query of the calendar. Adding events with future dates or dates up to 1 month in the past worked fine.
Here is the code I am using to add the event:
EKEvent *newCalendarEvent = [EKEvent eventWithEventStore:eventStore];
// In seconds; one hour default duration.
#define DURATION_OF_EVENT 60*60
newCalendarEvent.startDate = self.date;
// If I just use the startDate as the end date, then the height of the event in the calendar is really short.
NSDate *endEventDate = [[NSDate alloc] initWithTimeInterval:DURATION_OF_EVENT sinceDate:self.date];
newCalendarEvent.endDate = endEventDate;
newCalendarEvent.title = [self getEventTitle];
newCalendarEvent.calendar = cal;
NSError *error = nil;
[eventStore saveEvent:newCalendarEvent span:EKSpanThisEvent error:&error];
if (error) {
NSLog(#"CalendarIntegration.integrateDate: Error saving event: %#", error);
}
It turns out this seems to be a side effect of iOS7's Setting app setting under Mail, Contacts, Calendars > Synch. My setting was 1 month. By changing it to 3 months, I was able to create events up to 3 months old and have them displayed in the calendar. Note that I am talking about the calendar on the device that created the calendar event, in which case, I can't see how calendar synch would apply. But apparently, not all (e.g., Apple) would agree with this.

Comparing two NSDates constantly even outside the app

I decided for my first application i would create an alarm application. So far i understand to create two NSDate objects and compare them with isEqualToDate and UILocalNotifications for notifications. How do i continually compare the set date to the current date. Do i create a loop, or is there a more efficient way on Objective C? How do i continually check in the background?
[very new to objective c, sorry and thank you]
This what iv'e started:
NSDate * now = [NSDate date];
NSDate * later = [[NSDate alloc] initWithString:#"2001-03-24 10:45:32 +0600"];
NSComparisonResult result = [later compare:mile];
NSLog(#"%#", later);
NSLog(#"%#", mile);
You don't need to create loops or compare dates yourself. One way to have your alarm sound could be via a local notification. A quick sample code to schedule yourself a local notification:
// Initialize your notification
NSUserNotification *notification = [[NSUserNotification alloc] init];
// Set the title of your notification
[notification setTitle:#"Alarm finished!"];
// Set the text of your notification
[notification setInformativeText:#"My Text"];
// Set the time and date on which the notification will be delivered (in this case 60 seconds after the current time)
[notification setDeliveryDate:[NSDate dateWithTimeInterval:60 sinceDate:[NSDate date]]];
// Set the sound, this can be either nil for no sound, NSUserNotificationDefaultSoundName for the default sound)
[notification setSoundName:NSUserNotificationDefaultSoundName];
// Schedule the notification
[[NSUserNotificationCenter defaultUserNotificationCenter] scheduleNotification:notification];
If you don't want to use a local notification but want to execute something different once your alarm finishes, you could use NSTimer to execute your action once the alarm fires.