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)
}
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'm developing a simple app in Swift and I need to schedule a function execution every 24 hours. I'm aware of the method:
DispatchQueue.main.asyncAfter(deadline: .now() + 10.0, execute: {
self.functionToCall()
})
that could solve my problem but, is this the right solution for a 24 hours delay?
Thanks
Theoretically, this is possible.
The problem is that your app would have to run in the foreground for 24 hours, which is very unlikely to happen. Unfortunately, you can not run background tasks just like that.
The solution:
Just make it look like the function would execute in the background. Every time the update function is called, simply save the Int(Date().timeIntervalSince1970) to UserDefaults. This works like a timestamp and saves the last time you called your update function. Every time in the viewDidLoad()-function (not sure if it's called the same on Mac apps, but you can imagine what I mean) call:
If let timestamp = UserDefaults.standard.integer(forKey: "yourTimestampKey") {
let currentTimestamp = Date().timeIntervalSince1970
if (currentTimestamp - timestamp) > 86400 { // number of seconds in 24 hours
// the last time your function was updated was at least 24h ago
update()
}
}
That's how you can make it appear like it was updated in the background. I use this all the time in my apps and it works perfectly.
EDIT:
Maybe, just in case the app does indeed run 24 hours in a row, I would set up the upper function that you posted first as well.
I would like some advise on the best way to approach a problem I have.
I want my program to block until the current time is 60 seconds before a given time, using LocalTime in Java 8?
So it would be something like:
LocalTime time1 = LocalTime.of(13, 11)
LocalTime currentTime = LocalTime.now()
Then some code that implemented some logic like: Thread.sleep(until currentTime < time1 - 60 seconds)
Any help would be great, thanks!
Use the LocalTime minusSeconds method to get the time adjusted by 60 seconds (or use minusMinutes). Then use Duration.between to get the duration between the two times:
LocalTime time1 = LocalTime.of(13, 11);
LocalTime untilTime = time1.minusSeconds(60);
LocalTime currentTime = LocalTime.now();
Duration duration = Duration.between(currentTime, untilTime);
// TODO possibly check duration.isNegative()
Thread.sleep(duration.toMillis());
Well, converting a LocalTime to a LocalTime with 60 seconds difference is trivial. But while it is tempting to calculate a difference to LocalTime.now() to get a time to wait, there is the problem that time elapses while you’re calculating the difference, so the value is already inaccurate when you invoke the wait function.
While there is an imprecision in general when you’re waiting in a multi-tasking system, i.e. there will be an arbitrary execution speed and thread scheduling after the wait, you should avoid raising it additionally.
The better solution is to calculate a deadline, even if it might look slightly more complicated, and wait for reaching the deadline:
LocalTime target = LocalTime.of(12, 50).minusSeconds(60);
long deadLine = target.atDate(LocalDate.now()).atZone(ZoneId.systemDefault())
.toInstant().toEpochMilli();
while(System.currentTimeMillis() < deadLine) {
// in case you want to support interruption:
if(Thread.interrupted())
throw new InterruptedException();
LockSupport.parkUntil(target, deadLine);
}
This code allows you to decide whether to support interruption or not. Note that even if you don’t support it, the loop still will be needed to handle so-called spurious wakeups correctly. But while there will be elapsed time between the loop’s condition check and the parkUntil invocation, it will be handled due to the nature of a deadline, i.e. parkUntil will return immediately if the deadline has been reached in-between.
The first parameter is optional, i.e. you could also invoke parkUntil(deadLine) instead. It provides debugging hints about why the thread is waiting, e.g. when the argument has been specified, a thread dump would look like this:
"main" #1 prio=5 os_prio=0 tid=0x0000000002b20800 nid=0x2aa8 waiting on condition [0x0000000002a2f000]
java.lang.Thread.State: TIMED_WAITING (parking)
at sun.misc.Unsafe.park(Native Method)
- parking to wait for <0x000000076b007220> (a java.time.LocalTime)
at java.util.concurrent.locks.LockSupport.parkUntil(LockSupport.java:256)
…
showing what’s going on. Also, if the wait lasts long enough, another thread could invoke getBlocker and inspect the returned object.
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
I am trying to use the Joda Time library to help me schedule sending some messages to an Actor in Akka.
I would like to schedule sending emails every day at 8:30 AM. To do this, I have to tell the scheduler how many seconds (or milliseconds) to wait until the next message is sent.
I would like to account for daylight savings (to make sure it always fires around 8:30, and not 7:30 or 9:30) so I will use LocalDate and LocalTime.
So, basically, I have:
targetDate = LocalDate.now().plusDays(1) and targetTime = new LocalTime(8, 30)
and
rightNow = LocalDateTime.now()
I was wondering what is the best way to compose a targetDateTime based on targetDate and targetTime so I can use it to compute the time difference with rightNow
I know I can create a new LocalDateTime extracting all the values for the constructor from my targetDate and targetTime but: is there a more elegant way?
So far, I have settled for:
targetDateTime = targetDate.toLocalDateTime(targetTime)
secondsToWait = Seconds.secondsBetween(rightNow, targetDateTime)
Getting targetDateTime is easy if you have the targetDate and targetTime (as given in your question) :
targetDateTime = targetDate.toDateTime(targetTime);
Getting the seconds of the Duration between now and targetDateTime:
new Duration(new DateTime(), targetDateTime).getStandardSeconds();
The method is called standard seconds because it assumes every second to be a standard second of 1000 milliseconds. As its javadoc says, currently all Chronologies only have standard seconds.
But you can also simply use milliseconds (no conversion assumptions needed) :
new Duration(new DateTime(), targetDateTime).getMillis();
Disclaimer : I only just saw this was a scala question, so you may have to correct for any syntax differences, since I'm not versed in scala.