I need to schedule local notifications which I'd like to repeat each day from lets say at 23:00. But I do not want to start from today but from tomorrow.
If I schedule them using UNCalendarNotificationTrigger:
var dateInfo = DateComponents()
dateInfo.hour = 23
dateInfo.minute = 0
dateInfo.second = 0
let trigger = UNCalendarNotificationTrigger(dateMatching: dateInfo, repeats: true)
then the notifications will be received each day at 23:00 but will get notification for today as well if the above code is executed before 23:00.
Is there any good way to achieve that or I just should schedule 64 (the iOS limit for undelivered local notifications) different local notifications with exact dates?
Related
This question could be rephrased as: How to invoke a function if 2 seconds pass without an event (re)occurring?
I'm playing with SFSpeechRecogniser. While the user is speaking it sends continuous updates (maybe 2-3 per second). I'm trying to detect when the user stops speaking. If I don't receive any updates for (say) 2 seconds, I can assume that the user has paused speaking.
How to implement this in Swift?
I am aware that I could do:
var timer : Timer?
func f() {
on_event = { result, error in
print( "Got event, restarting timer" )
self.timer?.invalidate()
self.timer = Timer.scheduledTimer(withTimeInterval: 2.0, repeats: false) { _ in
print( "2s inactivity detected" )
self.timer?.invalidate()
NotificationCenter.default.post( name: inactivity_notification, object: nil )
}
}
}
But is it possible to do it without repeatedly creating and destroying the Timer instance (and thus creating a boatload of temporary Timer instances that never get used)?
One way to do it is to:
Record the current time when an event occurs
Set up a recurring timer with a granularity you are comfortable with (for example 0.25 seconds).
When the timer pops, check difference between current time and last event time. If that is greater than 2 seconds, fire your notification.
This is what I'd do if I had to recognize that a person had stopped typing for 2 seconds. Invalidating and creating timers at typing speed would be a lot of churn. You can tune this to your requirements depending on how close to exactly 2 seconds you need to be.
You could also do this by just having a timeSinceLastEvent variable, and set it to 0 when an event occurs. The recurring timer would increment this by the granularity, and check if it has reached 2 seconds and fire the notification if it had. This is cruder than doing the time math since the timer interval isn't guaranteed, but simpler.
Timer's .fireDate property is writable.
So every time a speech event occurs just do timer.fireDate = Date(timeIntervalSinceNow: 2)
I want to call a method at the same time every day (at the end of the day, like 23.59).
I understand to set a repeating method to be called I do like this:
let date = Date()
let timer = Timer(fireAt: date, interval: 86400, target: self, selector:
#selector(runCode), userInfo: nil, repeats: true)
RunLoop.main.add(timer, forMode: RunLoopMode.commonModes)
This repeats every 86400 seconds, which mean every day.
But how to set the date parameter to start at 23.59, the specific time I want. Currently, it just goes off at the time the code calls it.
Thanks very much
sounds like you might have to do silent notifications:
Silent Push Notification Payload
What is difference between remote notification and silent notification in iOS?
There is also a UNNotifcationRequest you can look into but it's not silent:
Use UNNotificationRequest (UserNotificationFramework) for data only local notification on iOS
My current project is a timer which uses a date picker to set the amount of time the user wants before the timer goes off (say 1 minute, 6 hours and two minutes etc.). The problem lies in the amount of time that the date picker believes it has been set for. Below is the code which I am using to set the time.
#IBOutlet weak var datePicker: UIDatePicker!
var timeAmount:Double = 0
#IBAction func startButton() {
timeAmount = Double(datePicker.countDownDuration)
let trigger = UNTimeIntervalNotificationTrigger(timeInterval: timeAmount, repeats: false)
}
Here it can be seen that the function startButton, sets the value of timeAmount to be the amount of time that the date picker is set for. This timeAmount value is then used in a local notification as the time.
The issue is that the datePicker.countDownDuration is never correct. If it is set for one minute, then timeAmount may return a value of 99 seconds, 62 seconds, 67 seconds etc. It is just completely random.
Maybe I do not entirely understand how the .countDownDuration feature works, however from everything I have read, this should return a value of 60 seconds.
Any thoughts and suggestions on the matter will be very much appreciated, thank you.
By default, the UIDatePicker will take the current second value for the calculation.
timeAmount = (number of minutes selected in picker * 60) + current time second value.
For example:
If the current time is 13:40:25 (1 PM 40 minutes 25 seconds) and you have selected one minute in the date picker, the value of timeAmount in this case is 85.
timeAmount = (1*60) + 25
This will solve your problem.
Go to your Storyboard and select UIDatapicker. Navigate to Date option in Attributes inspector.
Click the Dropdown and change it to Custom from Current Date.
You will see a new text field with the current time as the custom date.
Just change the second field to 00.
Run the App now. Now it will take 0 as the value for the second and you will able to see seconds value correctly based on the time you are choosing in the date picker.
Hope this will solve your problem.
I'm trying to get my app to call a function at specific time intervals. For example, I might want the function to be called every hour on the hour, so at 1:00 AM, 2:00 AM, and so on. I have tried doing this with an NSTimer, but I find that it has trouble staying in sync when resuming after the machine sleeps or is powered off. Is there a way for my app to detect when we have reached a specific date and time and to call a function at that time? Thanks.
You could try Grand Central Dispatch. Specifically use dispatch_walltime() to create a dispatch_time_t representing the time you want the job to run and then use dispatch_after() to submit the job to Grand Central Dispatch for execution at the specified time.
Run it every minute and test whether ≥ 1h has elapsed since the last invocation.
You could use a helper method similar to below in combination with the NSTimer. The timer could fire its selector function every sec/minute/etc in which you pass this helper a pair of currentDate/endDate and when the returned value is <= 0 then execute your timed event function once with a flag and move your endDate forward an hour.
func timeBetween(currentDate: NSDate, endDate: NSDate) -> Double
{
let calendar = NSCalendar.currentCalendar()
let components = calendar.components([.Second], fromDate: currentDate, toDate: endDate, options: [])
return Double(components.second)
}
Is there anyway to show the notification with swift every 15 seconds ? I checked that via
notification.fireDate=NSDate(timeIntervalSinceNow: 15)
but it doesn't work everytime it just showed once , how we can do it as a loop ?
You can't schedule a notification every 15 second. The minimum time between notifications it is 1 minute which it is also very unlikely needed.
var repeatInterval: NSCalendarUnit { get set }
Description The calendar interval at which to reschedule the
notification. If you assign a calendar unit such as weekly
(NSWeekCalendarUnit) or yearly (NSYearCalendarUnit), the system
reschedules the notification for delivery at the specified interval.
Note that intervals of less than one minute are not supported. The
default value is 0, which means that the system fires the notification
once and then discards it.
So just set it up as follow:
notification.repeatInterval = .Minute
You can set localNotification.repeatInterval property which as to be of type NSCalendarUnit