iOS UILocalNotification scheduled, but not fired - ios

I'm making an application where I want local notifications. And something strange is happening. I schedule the notification:
static func setNotification(body: String, departure: Double, notification_info: Dictionary<String, String> )
{
let notification = UILocalNotification()
notification.alertBody = body
notification.fireDate = NSDate(timeIntervalSinceNow: departure)
notification.alertAction = "ShowDetails"
notification.userInfo = notification_info
notification.soundName = UILocalNotificationDefaultSoundName
UIApplication.sharedApplication().scheduleLocalNotification(notification)
print("notification over: " + String(departure))
print("-------" + String( notification.fireDate ))
}
I print in how much seconds i am supposed to get an notification.
I go to background mode, and keep watching when I will get an notification. when the time has passed, I get no notification, even though I am sure I am in background mode. (within Xcode I look at the debug navigator > Energy Impact, and it is saying I am in background).
When I restart my phone, and run the application, it does show the notification. Everything works perfect. And then later, after some more testing and using the application, my notifications stop working again (even though the notifications are still scheduled. I am following all the scheduled notifications with:
UIApplication.sharedApplication().scheduledLocalNotifications
I am still new with Swift, and I have no idea why this is happening. It's making me crazy not knowing why my notification is not firing, even though it is scheduled and everything...
Could anyone help me? If you need more information, please ask.
Edit:
I did set the permissions
The notifications are set in the AppDelegate
The departure time definitely is right

I made a mistake by not adding an unique ID to the notification (notification.userInfo was not always unique), and overwrites the previous scheduled notification. Thats why it something does work and sometimes doesn't.
Fixed the problem by making it unique.
Thanks

Since iOS 8.0, You have to ask for permission for local notifications as remote notifications:
let notificationSettings = UIUserNotificationSettings(forTypes: UIUserNotificationType.Alert, categories: nil)
UIApplication.sharedApplication().registerUserNotificationSettings(notificationSettings)
See more details in Location Notifications

Related

Creating multiple local notifications at once fails

I'm working with local notification on iOS, but I'm having some problems when iOS tries to create the notifications. Some of them are created and some won't.
After reviewing my code a lot, I found that it was failing at the point where it was creating the local notification.
UIApplication.sharedApplication().scheduleLocalNotification(notification)
The only reason I could think of was that creating the notifications inside a loop, around 50-60 notifications, was too much for iOS to process. I'm doing it this way because all the notifications have a different time and different day, and belong to different things.
This is my block to create the local notifications:
let createdUid = self.generateNotificationUUID()
// create a corresponding local notification
let notification = UILocalNotification()
/* Time and timezone settings */
notification.fireDate = self.buildTime()
notification.repeatInterval = NSCalendarUnit.WeekOfYear
notification.timeZone = NSTimeZone.systemTimeZone()
/* Information settings */
notification.alertBody = "Sector \(notificationData["sector"]!): located at \(notificationData["name"]!) closes in 15 min."
notification.alertAction = "Open"
/* Badge settings */
notification.applicationIconBadgeNumber = UIApplication.sharedApplication().applicationIconBadgeNumber + 1
notification.soundName = "ring.caf"
notification.userInfo = ["UUID": createdUid, ]
/* Schedule the notification */
UIApplication.sharedApplication().scheduleLocalNotification(notification)
And all this code is inside a loop. The same loop before calling the notification creation, dynamically builds the notificationData array.
The notification data array contains the sector, the name, and the time and day.
Time and day is used to calculate the notification fire date.
Sector and Name are used for the alert body.
And all the four values are used to generate the UID (UUID).
If I put a print and remove the UIApplication.sharedApplication()... all the data looks good and what it needs to be.
I've tried, to solve the problem, using
dispatch_async(dispatch_get_main_queue()) {...}
and
dispatch_sync(dispatch_get_main_queue()) {...}
But with async I received the same result that I had without it, and using sync my screen freezes.
I kind of lost with this, I'm sure that my issues are because iOS doesn't process in time all the notification creation, but I dunno how to fix it.
I hope someone can help me, I'm using XCode 7.3.1 and Swift 2.2
From the documentation: https://developer.apple.com/library/ios/documentation/iPhone/Reference/UILocalNotification_Class/
An app can have only a limited number of scheduled notifications; the
system keeps the soonest-firing 64 notifications (with automatically
rescheduled notifications counting as a single notification) and
discards the rest.

How to Reset Local Notifications when App Re-opens

I am developing a reminder app with custom Repeat Intervals for local notifications. What I basically want is the DueDate notification to fire then subsequent notifications fire afterwards.
So Notification1.fireDate = the DueDate.date
Notification2.fireDate = DueDate.date.dateByAdding(1000)
& continue for 10 or so times. Then when the app becomes active again, I want the line of notifications to loop again but start after the last notification, like a Queue.
This is all to create the illusion of custom repeat intervals. This is where I got the idea from, so it can be done https://stackoverflow.com/a/5765870/5601784
If you are not changing the fireDate, then there is no point in deleting the previously set notification and setting it again. However, to delete all the notification that your app has set you can do this.
UIApplication.shared.cancelAllLocalNotifications()
or
let app: UIApplication = UIApplication.shared
for event in app.scheduledLocalNotifications! {
let notification = event as UILocalNotification
app.cancelLocalNotification(notification)
}
print(app.scheduledLocalNotifications!.count))//prints -- 0
Then you can set the UILocalNotification with the new information.

Setting Reminders/Alarms in iOS8-iOS9

Main question: Should I be using local notifications, alarms, or reminders if I want attach due dates to tasks in my app? I want them to get a notification even if the app isn't running when the deadline arrives.
I found this tutorial on using UILocalNotification which it says can:
gives us the ability to cast notifications to a user without running the application
However, it was written six years ago and also states that this was introduced in iOS4. I know that a lot changes over 5 iOS versions.
I also read, alternatively, that I could use Event Kit. However, that seems more complicated than UILocalNotification.
Lastly, I could use probably take the current date/time and reminder date/time and create a timer to countdown.
So if I just want to attach due dates to tasks in my app (they don't need to show up in reminders or in the calendar), what's the best method and why?
I found following chunk of code here. This is also a good tutorial for how to create event in application.
var notification = UILocalNotification()
notification.alertBody = "Todo Item \"\(item.title)\" Is Overdue" // text that will be displayed in the notification
notification.alertAction = "open" // text that is displayed after "slide to..." on the lock screen - defaults to "slide to view"
notification.fireDate = item.deadline // todo item due date (when notification will be fired)
notification.soundName = UILocalNotificationDefaultSoundName // play default sound
notification.userInfo = ["UUID": item.UUID, ] // assign a unique identifier to the notification so that we can retrieve it later
notification.category = "TODO_CATEGORY"
UIApplication.sharedApplication().scheduleLocalNotification(notification)

Local Notification Not Firing

I'm trying to use local notification, this is my code:
appdelegate
application.registerUserNotificationSettings(UIUserNotificationSettings(forTypes: [UIUserNotificationType.Sound, UIUserNotificationType.Alert, UIUserNotificationType.Badge], categories: nil))
notificationViewController
let localNotification:UILocalNotification = UILocalNotification()
var BDate = friend.birthday.componentsSeparatedByString("/")
let date = NSDate.date(year: 2015, month: Int(BDate[1])!, day: Int(BDate[0])! - daysBefore, hour: hour, minute: min, second: 0)
localNotification.soundName = "notificationSound.mp3"
localNotification.alertBody = friend.fullName + " has a birthday today!"
localNotification.fireDate = date
localNotification.timeZone = NSTimeZone.localTimeZone()
localNotification.repeatInterval = NSCalendarUnit.Year
UIApplication.sharedApplication().scheduleLocalNotification(localNotification)
friend.birthday is a string - "DD/MM/YYYY"
I'm calling the setNotification function for every friend in a friends array. When there are only one or two friends I get the notification but one there are ~100+ I no longer get the notification.
I know the fireDate is correct, I checked it.
Why the code isn't working?
Each app on a device is limited to 64 scheduled local notifications. The system discards scheduled notifications in excess of this limit, keeping only the 64 notifications that will fire the soonest. Recurring notifications are treated as a single notification.
You can find more detail here
Looks like you're really exceeded the notifications limit. There's several tips and guidelines that might help:
Try to check your date versus NSDate() and schedule notification only if date.timeIntervalSinceReferenceDate > NSDate().timeIntervalSinceReferenceDate (There is a compare method in NSDate, but I prefer to compare raw values)
Scheduling local notifications one-by-one is very expensive for application performance, so you can form an array of notifications and schedule them all at once. Use UIApplication.sharedApplication().scheduledLocalNotifications property for that purpose.
This will allow you effectively reschedule all notifications on every application launch. For example in applicationDidFinishLaunching() delegate method.
And also, this will give you another advantage: you can easily check for notifications limit and, if necessary, add/replace 64-th notification with prompt to user to launch your app to allow it to schedule more notifications. This is a common practice for many applications to deal with Apple's limitations.

iOS Local Notifications Testing

In testing my local notifications, for some reason setting the date and time on my iOS device does not trigger my local notification to appear. My notification's fire date is set to be several days in the future. If I do wait a few days then I will see my local notification.
Why am I not seeing my local notification by setting the date and time on my device?
Below is a sample:
playNotification.FireDate = DateTime.Now.AddHours(71.67f);
playNotification.AlertAction = "Alert text";
playNotification.AlertBody = "Alert body";
playNotification.SoundName = UILocalNotification.DefaultSoundName;
playNotification.ApplicationIconBadgeNumber = badgeCount;
UIApplication.SharedApplication.ScheduleLocalNotification(playNotification);
I should mention that I changed 'AddHours' to 'AddSeconds' and tested this by waiting the specified number of seconds, and the notifications fired as expected. But somehow changing the date and time on my device does not.
You need to set the timeZone of the notifications. By default, the timeZone is set according to your location so it does not affect if you manually change your date and time. To achieve this, you need to set the timeZone to systemTimeZone().
Like this:
notification.timeZone = NSTimeZone.systemTimeZone()
I know this is in swift, but I know very little objective-c.
Hope this helps. :)

Resources