Remove UILocalNotification when cell is removed containing date - ios

i am making reminder application there is table view and there is dates in cell and when that cell date become todays day UILocalNotification fires. for that i am using following code
-(void)notification {
// logic for local notification start
NSDateFormatter *Form = [[NSDateFormatter alloc] init];
[Form setDateFormat:#"dd/MM/yyyy"];
UILocalNotification *notification = [[UILocalNotification alloc] init];
for (int i=0;i<_convertedBdates.count;i++)
{
NSDate *date =[Form dateFromString:[_convertedBdates objectAtIndex:i ]];
// NSLog(#"date%#",date);
if(notification)
{
notification.fireDate = date;
notification.timeZone = [NSTimeZone defaultTimeZone];
notification.alertBody = [NSString stringWithFormat:#"Today is %#\'s Birthday",[_combinedNameArray objectAtIndex:i]];
notification.alertAction = #"View";
notification.soundName = UILocalNotificationDefaultSoundName;
notification.applicationIconBadgeNumber = 1;
[[UIApplication sharedApplication] scheduleLocalNotification:notification];
}
}
// local notification logic ends here
}
now i have also implemented functionality of deleting cell from table view
now my problem is cell gets removed but its notification not there is no cell but when that date comes then notification fire.
how should i remove that particular notification when that cell is removed?

Edited: My initial answer was wrong, because I didn't realize that the OS copies UILocalNotifications when you schedule them, rather than just retaining them. So...
There are two ways to do this, as far as I can tell.
Cancel all notifications when a row is deleted, and then reschedule the remaining ones.
This is going to be more efficient if you don't have many notifications scheduled, and it will definitely be much easier to code. (Note: I don't know enough about the low-level things at work to say which is necessarily more efficient, but my guess is that the difference isn't really important.)
Whenever a row is deleted, simply call
[[UIApplcation sharedApplication] cancelAllLocalNotifications];
Then update _convertedBDates appropriately, and finally call your notification method again to reschedule new local notifications for those events that are still around.
Create unique identifiers for your local notifications
This is possibly the more efficient way, if you can come up with a good way to make those unique identifiers and if you have a lot of notifications scheduled. (Emphasis on possibly). One possibility is to use the time at which the notification will fire, if you can guarantee that no two notifications will fire at the same time. Other possibilities are the label for the notification (again if you can be sure of uniqueness). Whatever you decide to use for your unique identifier, you can store it by adding this outside your for loop:
self.uniqueIDArray = [[NSMutableArray alloc] init];
(where uniqueIDArray is an NSMutableArray* #property of your class) and then this right before you schedule the notification:
[uniqueIDArray addObject:whateverObjectYouUseForTheUniqueID];
notification.userInfo = [[NSDictionary alloc] initWithObjects:whateverObjectYouUseForTheUniqueID
forKeys:#"uniqueID"];
Then, in whatever method you're using to delete the cells, you would do something like this:
uniqueIDToDelete = [self.uniqueIDArray objectAtIndex:indexOfCellBeingDeleted];
NSArray *scheduledNotifications = [[UIApplication sharedApplication] scheduledNotifications];
UILocalNotification *notifToDelete;
for (UILocalNotification *notif in scheduledNotifications) {
if ([[notif.userInfo objectForKey:#"uniqueID"] isEqual:uniqueIDToDelete]) {
[[UIApplication sharedApplication] cancelLocalNotification:notif];
}
}
[self.uniqueIDArray removeObjectAtIndex:indexOfCellBeingDeleted];

I think you shouldn't use cell as source for notification. Use data model instead. Also you could remove notification easily
UPDATE
Model *model = [_array objectAtIndex:indexPath.row]; model.notificationID = // here you store created notification identifier
[[UIApplication sharedApplication] scheduledLocalNotifications] // contains all local notifications, you should search you need by ID and remove it using cancelLocalNotification method.
P.S. notification ID you can store in notification userInfo

Try this
NSArray *notificationArray = [[UIApplication sharedApplication] scheduledLocalNotifications];
UILocalNotification *notif = [notificationArray objectAtIndex:indexPath];
[[UIApplication sharedApplication] cancelLocalNotification:notif];

Related

UILocalNotification with custom repeat Intervals other than NSCalendarUnits [duplicate]

I am trying to setup a UILocalNotification to run every 30 seconds using the following logic, however it seems to be misbehaving. There are 2 issues:
When the notifications get fired there seems to be a lot of them all at once, rather than 1 every 30 seconds.
The application icon badge number doesn't seem to increase. It just stays at 1.
Please can someone help me work out what I've done wrong?
// Create 'base' notification we can use
UILocalNotification *baseNotification = [[UILocalNotification alloc] init];
baseNotification.timeZone = [NSTimeZone defaultTimeZone];
baseNotification.repeatInterval = NSMinuteCalendarUnit;
baseNotification.alertBody = #"My Message.";
baseNotification.alertAction = #"My Alert Action";
baseNotification.soundName = UILocalNotificationDefaultSoundName;
UILocalNotification *alertOne = [baseNotification copy];
alertOne.applicationIconBadgeNumber++;
alertOne.fireDate = [[NSDate date] dateByAddingTimeInterval:30];
[[UIApplication sharedApplication] scheduleLocalNotification:alertOne];
UILocalNotification *alertTwo = [baseNotification copy];
alertTwo.applicationIconBadgeNumber++;
alertTwo.fireDate = [[NSDate date] dateByAddingTimeInterval:60];
[[UIApplication sharedApplication] scheduleLocalNotification:alertTwo];
Try this one.
UILocalNotification *baseNotification = [[UILocalNotification alloc] init];
baseNotification.timeZone = [NSTimeZone defaultTimeZone];
baseNotification.repeatInterval = NSMinuteCalendarUnit;
baseNotification.alertBody = #"My Message.";
baseNotification.alertAction = #"My Alert Action";
baseNotification.soundName = UILocalNotificationDefaultSoundName;
UILocalNotification *alertOne = [baseNotification copy];
alertOne.fireDate = [[NSDate date] dateByAddingTimeInterval:30];
alertOne.applicationIconBadgeNumber = [[UIApplication sharedApplication]applicationIconBadgeNumber]+1;
UILocalNotification *alertTwo = [baseNotification copy];
alertTwo.fireDate = [[NSDate date] dateByAddingTimeInterval:60];
alertTwo.applicationIconBadgeNumber = [[UIApplication sharedApplication]applicationIconBadgeNumber]+1;
There is currently no way possible to achieve custom repeats with intervals.
However, the notification system can queue up to 64 notifications so the closest thing you could do is to manually set as many notifications as you need (with each one having a different number for the badge and a different fireDate) and then have your notifications list updated by setting new ones when you're running low on them.
This will return how many notifications you've in queue:
[[[UIApplication sharedApplication] scheduledLocalNotifications] count]
There's also this post that I would recommend you reading for further help:
iOS badge number live update
Good luck!
Regarding second point, you're increasing the badge number of the copy not the original notification. And since the original has a zero badge number you'll always get a copy with zero badge number too and increasing it will make it always 1.
The solution is to increase the badge of the original notification right before making the copy:
...
baseNotification.applicationIconBadgeNumber++;
UILocalNotification *alertOne = [baseNotification copy];
alertOne.fireDate = [[NSDate date] dateByAddingTimeInterval:30];
[[UIApplication sharedApplication] scheduleLocalNotification:alertOne];
baseNotification.applicationIconBadgeNumber++;
UILocalNotification *alertTwo = [baseNotification copy];
alertTwo.fireDate = [[NSDate date] dateByAddingTimeInterval:60];
[[UIApplication sharedApplication] scheduleLocalNotification:alertTwo];
According NSObject class reference :
copy - Returns the object returned by copyWithZone:
And copyWithZone returns a shallow copy.
So its like all notification have same properties .
Hence , badge number is always "1" and fireDate is same for all notifications. i.e. last one that you apply .
Hence , notifications get fired at same time.
Hope , it helps.
I think you get a lot of notifications every 30 seconds is because you did not cancel previous notifications. Add this line at the top of your code.
[[UIApplication sharedApplication] cancelAllLocalNotifications];

Clear already displayed local notification programmatically

I need to clear already displayed local notification from Notification Centre programmatically. Following this link I implemented suggested solution, but the problem is that eventArray from this example always has 0 elements. When I swipe down to display Notification Centre I see 4 notifications that I've created previously. So in this case I expect this array to have 4 elements, but it has 0. Any idea why is this so? I've tried on iOS 8.3 and 9.2.1 and array is 0 on both of them.
iOS has 2 ways of presenting local notifications:
From Notification Center:
You can't swipe away notification from left to right.
You can swipe notification from right to left (deleting single notification from the list).
You can click on the notification, after which your app will start and notification will be removed from Notification Center (handled by iOS system)
From Lock screen:
Available only if you enable this setting from iPhone/iPad settings: http://www.imore.com/how-disable-notification-center-lock-screen-your-iphone-and-ipad
You can swipe notification from left to right (your app will be started, handled by iOS). In this case notification from Notification Center is not deleted (iOS doesn't delete it, and doesn't allow deleting a single notification from code after notification is already presented to the user in Notification Center).
You can swipe notification from right to left (deleting single notification from the list, handled by iOS. Notification Center notification is also deleted, handled by iOS).
You can't click on the notification.
EDIT:
Here is code sample how I did it:
UILocalNotification* localNotification = [[UILocalNotification alloc] init];
localNotification.alertBody = #"1";
localNotification.alertTitle = #"1";
localNotification.userInfo = uniqueDictIdentifier1;
[[UIApplication sharedApplication] presentLocalNotificationNow:localNotification];
UILocalNotification *localNotification2 = [[UILocalNotification alloc] init];
localNotification2.alertBody = #"2";
localNotification2.alertTitle = #"2";
localNotification2.userInfo = uniqueDictIdentifier2;
[[UIApplication sharedApplication] presentLocalNotificationNow:localNotification2];
....
//2 more notifications are created like this
And then there is code for filtering all notifications:
NSArray *eventArray = [[UIApplication sharedApplication] scheduledLocalNotifications];
for (int i=0; i<[eventArray count]; i++) {
UILocalNotification* oneEvent = [eventArray objectAtIndex:i];
NSDictionary *userInfoCurrent = oneEvent.userInfo;
if ([userInfoCurrent isEqualToDictionary:uniqueDictIdentifier1]) {
[[UIApplication sharedApplication] cancelLocalNotification:oneEvent];
break;
}
}
For saving a notification for a unique id
NSDictionary * infoDict = #{ #"alarmUiqueId" : uID,
};
NSLog(#"%#",infoDict);
NSDateComponents *comp = [[NSCalendar currentCalendar] components:NSCalendarUnitSecond
fromDate:fireDate];
fireDate = [fireDate dateByAddingTimeInterval:-comp.second];
UILocalNotification *localNotif = [[UILocalNotification alloc] init];
localNotif.fireDate = fireDate;
localNotif.timeZone = [NSTimeZone localTimeZone];
localNotif.alertBody = desString;
localNotif.userInfo = infoDict;
localNotif.repeatInterval = NSCalendarUnitDay;
[[UIApplication sharedApplication] scheduleLocalNotification:localNotif]
and for delete a paritcular notification write this code.
NSArray *notificationArray = [[UIApplication sharedApplication] scheduledLocalNotifications];
for(UILocalNotification *notification in notificationArray)
{
NSLog(#"%#",[notification.userInfo valueForKey:#"alarmUiqueId"]);
if ([[notification.userInfo valueForKey:#"alarmUiqueId"] isEqualToNumber: health.uniqueId])
{
[[UIApplication sharedApplication] cancelLocalNotification:notification] ;
}
}
My understanding is below:
You can not get the information of already notified LocalNotification with scheduledNotifications.
My resolution is that just keep UILocalNotification instance in your singleton object in your application, and call cancelLocalNotification with the instance when you want to delete from Notification Center.
Is this could be your help ?

UILocalNotification with repeat-once behaviour like in Messages App

I have simple UILocalNotification:
UILocalNotification *notification = [[UILocalNotification alloc] init];
notification.alertBody = #"Message";
notification.alertAction = #"Action";
notification.soundName = UILocalNotificationDefaultSoundName;
notification.category = kCategoryIdentifier;
[[UIApplication sharedApplication] presentLocalNotificationNow:notification];
Is it possible, to repeat notification once, for example after two minutes? I want behaviour exacly, like in Messages app.
I have tried to set repeatInterval property of notification object, but:
Notification will be presented to user every two minutes, not repeated only once
System shows to user new notification, not repeat the old one. User see two notifications, one with timestamp 2 minutes after another.
Which is not what I've expected.
Also, because of second reason, I don't want to schedule two separate notifications.
Edit: In my app time when something happend is very important. Because of that, in lock screen, when notification is repeated, I want user to know that is something that happend earlier, not in time when notification arrives. So repeated notification should have timestamp of first notification.
Yes, you can set repeatInterval.
See documentation here
The calendar interval at which to reschedule the notification.
Declaration SWIFT var repeatInterval: NSCalendarUnit OBJECTIVE-C
#property(nonatomic) NSCalendarUnit repeatInterval
try this code
localNotif.timeZone = [NSTimeZone systemTimeZone];
localNotif.alertBody = #"Message";
localNotif.alertAction = #"View";
localNotif.soundName = UILocalNotificationDefaultSoundName;
localNotif.applicationIconBadgeNumber=1;
NSLog(#"LocalNotif.soundName %#",localNotif.soundName);
for (int i=0; i<20; i++)
{
localNotif.fireDate = [repeatAlarm dateByAddingTimeInterval:120*i];
[[UIApplication sharedApplication] scheduleLocalNotification:localNotif];
}

Perform Action At DatePicker Time

I need to send a text message when the current time equals the time selected in the UIDatePicker. How might I do this? You don't need to include the code to send the message, I already have that coded. I've tried all sorts of things with NSTimer and if - then statements but none have worked.
Edit: Since I wrote this question I've found a better way to do things. I just need to set a local notification and when received execute my code with -(void)didRevieveLocalNotification. Here is what I have so that any googlers can hopefully be helped.
NSDate *pickerDate = [self.datePicker date];
//Set Local Notification
UILocalNotification *notif = [[UILocalNotification alloc] init];
notif.fireDate = pickerDate;
notif.timeZone = [NSTimeZone defaultTimeZone];
//----------------------------------------------------------------------
notif.alertBody = #"Tap to send your text message!";
notif.alertAction = #"send message...";
notif.soundName = #"sms_alert_nova.caf";
notif.applicationIconBadgeNumber = [[UIApplication sharedApplication] applicationIconBadgeNumber] + 1;
[[UIApplication sharedApplication] scheduleLocalNotification:notif];
well i would use a local notification... something like this
UILocalNotification *notification = [[UILocalNotification alloc] init];
notification.fireDate = theDate //The date that your picker has selected
notification.alertBody = #"Hey, the time just expired!"
notification.applicationIconBadgeNumber = 1;
[[UIApplication sharedApplication] scheduleLocalNotification:notif];
Then in your AppDelegate
- (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification {
//Code to manage the notification logic
}
Hope this helps, the user will get the alert even if on background.. if on background the user must click the alert to let your application know that the local notification triggered, if he does (or he is on your app already, then the app delegate method will trigger letting your app know that the notification fired...
Hope this helps!

Obtaining a list of existing UILocalNotifications and modifying their dates

I'm trying to schedule several UILocalNotifications, and I need to have access to the already created notifications.
Is it possible to have a list/array of all the UILocalNotifications created? Can I edit the fire date of an existing local notification?
This is the code I use for creating local notifications:
UILocalNotification* localNotification = [[UILocalNotification alloc] init];
localNotification.fireDate = pickerDate;
localNotification.alertBody = textFieldName.text;
localNotification.alertAction = #"Item date expired!";
localNotification.timeZone = [NSTimeZone defaultTimeZone];
localNotification.applicationIconBadgeNumber = [[UIApplication sharedApplication] applicationIconBadgeNumber] + 1;
you can get all UILocalNotifications with below code
UIApplication* objApp = [UIApplication sharedApplication];
NSArray* oldNotifications = [objApp scheduledLocalNotifications];
and also you can cancel that Notification with bellow code..
if ([oldNotifications count] > 0)
[objApp cancelAllLocalNotifications];
Also see one basic demo with tutorial for UILocalNotification from below link
iphone-programming-tutorial-local-notifications
to retrieve current notifications
NSArray *currentNotifications = [[UIApplication sharedApplication] scheduledLocalNotifications];
edit the content of this array (you might have to create a mutable copy first) and then set it back using
[[UIApplication sharedApplication] setScheduledLocalNotifications:myNotifications];
myNotifications containing both the old pending notifications and your new ones, it will override the old values, so by editing the fireDate of the UILocalNotification objects in this array you can change the date they will be fired at.
I think you want this.
[[UIApplication sharedApplication] scheduledLocalNotifications]
Yes, you can get all local notification list from below statement:
[[UIApplication sharedApplication] scheduledLocalNotifications];
And For edit, i have not tried it but yes, can are able to modify fire date of notification.
But my suggestion is, get all other detail of notification and delete and recreate new notification.
Thanks

Resources