iOS check if a UILocalNotification condition occurs - ios

I read a lot of documentation and code about UILocalNotification. My alert occurs when the condition (a calculated value raise) a limit.
With localNotification.repeatInterval = NSHoursCalendarUnit
My Notification is resent every hours. How can I ask LocalNotificationCenter to make a calculation BEFORE sending (or not) the notification?
For exemple:
Value == 1 -> Notification, Value is one.
Every hours recalculate Value if Value changed -> Notification, value is changed
Thanks in advance for your help,
Jacques

Unfortunately you cannot set your own constraints when scheduling a local notification. The only thing you can do is to ignore the notification when it fires. (But when the application is closed you cannot do anything about it)

Related

iOS: OperationQueue.schedule(after: Date) that cannot be triggered by date change

Problem
I need to get a callback when at least X amount of time has passed since the date for the callback has been set.
Example 1:
This would have worked great, but it's possible to trigger an execution of the block by setting the date earlier than the correct time right now:
let responseDate = Date().advanced(by: 60) // 1 min
OperationQueue.current.schedule(after: .init(responseDate), {
print("the time is now!") // possible to set the current date 1 min before
}
On the other hand, the solution for getting a current uptime from this answer works great, but it requires timer constantly running to check if we're close to date.
Is it possible to combine these two approaches and somehow "attach" a callback to KERN_BOOTTIME, so that the OS will call my method when the boottime reaches a certain value?
I'm looking as well to alternative engineering solutions that satisfy two criterias:
It should not be possible to trigger the callback by resetting the device date to some arbitrary value in the past
If the device has been put to sleep (e.g. by pressing the on/off side button), the clock should still be "ticking", so that the method will be called back while the app is running in the background.
More details:
Backgrounding / app termination is out of scope
The main point is to prevent a bypass by switching the date backwards in the settings.

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.

Local Notification for Alarm Snooze

I am working on an alarm application and I am using local notification for that. Now I want to add snooze functionality to my alarm and alert show minimum distance 1 minute.
I am set Multiple alarm in my application so how can I managed it's?
UILocalNotification instances have a userInfo property of type NSDictionary. This can be used for storing information that you can later use for identifying what the notification was for.
For example, you could add the following code before firing the notification:
notification.userInfo = #{kAlarmIdentifier: alarm.identifier"};
where kAlarmIdentifier is a constant string used as a key. Then, when the notification is triggered, you can get the alarm that caused it with something like:
MYAlarm *alarm = [alarmManager getAlarmForIdentifier:notification.userInfo[kAlarmIdentifier]];

Update iOS icon badge number

I have a icon badge number update requirement. The app tracks tasks. I want the app to have a badge displaying the number of tasks due on each day. There are basically two cases when the badge number needs to be updated:
Midnight every day.
If new tasks are added or tasks are removed.
I know how to handle the second case. I can set badge number in the applicationResignActive func. However, the midnight automatic update is trick for me. To update the badge number, I need to call a func of the app to count the tasks that due on the day. However, in midnight, the app may be in all possible situations: foreground, background and not running. How can I do this? Thank you.
=====================================
To be clearer with my requirement, I would like the badge number to be updated everyday correctly, even the user never opens the app for a whole day or for consecutive several days. Also, I would try to avoid server side support because the app is a standalone app so far. Much appreciated for any help.
=====================================
Final update: I accepted Vitaliy's answer. However, his answer requires the app to be opened at least once every day. Otherwise, the event won't fire and the badge number cannot be updated.
Also, in my case, every time the app enters background event fires, I have to remove the existing notification and schedule a new one, with the up-to-dated badge number recalculated.
I am still interested in some way to handle the case that the app is not opened every day, how can you make sure the badge number is correct. So far, the easiest way is to setup some server and let it push notifications to the app regularly.
You can achieve it with UILocalNotification:
When app goes to background, calculate exact badge count number for nearest midnight
Schedule UILocalNotification at the nearest midnight with your calculated badge count
You will get notification at midnight, and app's badge count will be updated
Example code:
- (void)applicationDidEnterBackground:(UIApplication *)application {
// Calculate nearest midnight or any other date, which you need
NSDate *nearestMidnight = [self nearestMidnight];
// Create and setup local notification
UILocalNotification *notification = [UILocalNotification new];
notification.alertTitle = #"Some title";
notification.alertBody = #"Some message";
notification.fireDate = nearestMidnight;
// Optional set repeat interval, if user didn't launch the app after nearest midnight
notification.repeatInterval = NSCalendarUnitDay;
// Calculate badge count and set it to notification
notification.applicationIconBadgeNumber = [self calculateBadgeCountForDate:nearestMidnight];
[application scheduleLocalNotification:notification];
}

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