Enable/disable a perticular UILocalNotification and set multiple notification once - objective-c

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;
}
}

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.

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.

Application icon badge number not increasing : Xcode

I am facing a problem with push notification application badge number value updation.
I am doing like:
-(void)application:(UIApplication *)application
didReceiveRemoteNotification:(NSDictionary *)userInfo {
UIApplicationState state = [application applicationState];
if (state == UIApplicationStateActive) {
// do stuff when app is active
}else{
// do stuff when app is in background
[UIApplication sharedApplication].applicationIconBadgeNumber =
[UIApplication sharedApplication].applicationIconBadgeNumber+1;
/* to increment icon badge number */
}
}
But, the icon is showing the badge number as '1' always, and it is not incrementing when more notifications are there/ one notification came after another.
Any advice is appreciable...
The badge number is set by the operating system when you receive a JSON notification payload that resembles the following:
{
"aps" : {
"alert" : "New notification!",
"badge" : 2
}
}
As you see, it's the server who is responsible for setting the correct number in the badge key. Your server needs to track or compute the number of pending notifications for each user and generate the badge number before sending the notification to Apple.
The client responsibility is to clear the notification badge, or decrement it, when the user sees a notification. The code to do so is
application.applicationIconBadgeNumber = application.applicationIconBadgeNumber - 1; // Decrement counter
or
application.applicationIconBadgeNumber = 0; // Reset counter assuming the user is able to see all notifications at once.
you can create a static variable instead, and assign it to the applicationIconBadgeNumber:
static int i=1;
[UIApplication sharedApplication].applicationIconBadgeNumber = i++;
I had the same problem and solved it by creating int. variable in class.h
like this :
a custom class.H
#property int badge;
a custom class.M
-(id)init{
_badge=0;
self = [super init];
if (self) {
}
return self;}
-(void)reminderCreator:(NSDate*)onTime withText:(NSString*)text{
_badge += 1;
UILocalNotification* localNotification = [[UILocalNotification alloc] init];
localNotification.fireDate = onTime;
localNotification.alertBody = text;
localNotification.soundName=UILocalNotificationDefaultSoundName;
localNotification.applicationIconBadgeNumber=_badge;
[[UIApplication sharedApplication] scheduleLocalNotification:localNotification]; }
so if you initialize this custom class, somewhere (maybe at your viewController) and then call the reminderCreator method several times to setup few localNotifications, it will assign incremented number to each notification.
+1 if this helped :)
The -(void)application:didReceiveRemoteNotification: will only be called when your app is running in the foreground.
If you want the badge to be increase when your app isn't running you should set the badge number in the push notification payload.
You should there for keep track of the badge number server side, since the badge property of the push notification payload will be use as the badge number. It will not increment the badge number for you.
Since the system handles the incoming push notifications your app is not informed of received push notifications for you app. Only when you app is running in foreground will the -(void)application:didReceiveRemoteNotification: be called. There is no way to get you app to repsond to push notification when it is not in the foreground.
Yes it seems that it always returns badgeNumber 1 in spite it has value increased to 2.
when using such code:
// update badge count
let currentBadgeCount = UIApplication.shared.applicationIconBadgeNumber
let badge = (aps["badge"] as? Int) ?? 1
UIApplication.shared.applicationIconBadgeNumber = currentBadgeCount + badge
so I think the only solution will be to store it in UserDefaults and then update value of UserDafaults and then it is set then update badge count?
This should work:
static var notificationsCount: Int {
set {
let userDefaults = UserDefaults(suiteName: SharedAppData.appGroup)
userDefaults?.set(newValue, forKey: "notificationsCount")
UIApplication.shared.applicationIconBadgeNumber = newValue
}
get {
let userDefaults = UserDefaults(suiteName: SharedAppData.appGroup)
return userDefaults?.integer(forKey: "notificationsCount") ?? 0
}
}
And then
SharedAppData.notificationsCount = 0 // to reset badge count
And this to increment
// update badge count
SharedAppData.notificationsCount += 1

Stop local notification

I have a problem below:
When minimize app to background by press home button, create a local notification for pop-up every 5 minutes.
Remove app from background.
-->My expected then pup-up just only show when app exist and it's discarded when remove app from background.
My issue that local notification still active and it still showing pop-up every 5 minutes after remove it from background.
How can i stop it?
Please help me!
Thanks in advanced.
Put this in application delegate. It will remove all local notifications when the application enters background.
- (void)applicationDidEnterBackground:(UIApplication *)application
{
[[UIApplication sharedApplication] cancelAllLocalNotifications];
}
If you don't want to cancel all notifications... I've set up a unique identifier stored in the notification's userInfo dictionary. When I want to delete I fast enumerate through all notifications and pick out the correct one for deletion.
My stumbling blocks here were remembering to store the UUID I'd created for the notification and also remembering to use isEqualToString in the fast enumeration. I guess I could also have used a specific name string instead of a unique identifier. If anyone can let me know a better method than fast enumerating please let me know.
#interface myApp () {
NSString *storedUUIDString;
}
- (void)viewDidLoad {
// create a unique identifier - place this anywhere but don't forget it! You need it to identify the local notification later
storedUUIDString = [self createUUID]; // see method lower down
}
// Create the local notification
- (void)createLocalNotification {
UILocalNotification *localNotif = [[UILocalNotification alloc] init];
if (localNotif == nil) return;
localNotif.fireDate = [self.timerPrototype fireDate];
localNotif.timeZone = [NSTimeZone defaultTimeZone];
localNotif.alertBody = #"Hello world";
localNotif.alertAction = #"View"; // Set the action button
localNotif.soundName = UILocalNotificationDefaultSoundName;
NSDictionary *infoDict = [NSDictionary dictionaryWithObject:storedUUIDString forKey:#"UUID"];
localNotif.userInfo = infoDict;
// Schedule the notification and start the timer
[[UIApplication sharedApplication] scheduleLocalNotification:localNotif];
}
// Delete the specific local notification
- (void) deleteLocalNotification {
// Fast enumerate to pick out the local notification with the correct UUID
for (UILocalNotification *localNotification in [[UIApplication sharedApplication] scheduledLocalNotifications]) {
if ([[localNotification.userInfo valueForKey:#"UUID"] isEqualToString: storedUUIDString]) {
[[UIApplication sharedApplication] cancelLocalNotification:localNotification] ; // delete the notification from the system
}
}
}
// Create a unique identifier to allow the local notification to be identified
- (NSString *)createUUID {
CFUUIDRef theUUID = CFUUIDCreate(NULL);
CFStringRef string = CFUUIDCreateString(NULL, theUUID);
CFRelease(theUUID);
return (__bridge NSString *)string;
}
Most of the above has probably been lifted from StackOverflow at sometime in the last 6months. Hope this helps

UILocalNotification repeatInterval

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.