I need to do some time math in iOS, with Swift.
I have to use dispatch_walltime
. I hope that can be taken as axiomatic. Where time math is concerned, I think I'm likely to get the response "just use NSDate
," but please take it on faith: I am bound to dispatch_walltime
.
Now, it's plain why someone might suggest NSDate
, because when you're using NSTimeInterval
and NSDate
and that good stuff, it's pretty easy to make custom timestamps and compare them and do all kinds of time math.
But I have to use dispatch_time_t
, and specifically dispatch_walltime
created like this:
//Get the timeInterval of now.
let nowInterval = NSDate().timeIntervalSince1970
//Make a timespec from it.
var nowStruct = timespec(tv_sec: Int(nowInterval), tv_nsec: 0)
//Make a walltime definition from that.
let referenceWalltime = dispatch_walltime(&nowStruct, 0)
Later on I need to use that reference time in various ways. For instance, I need to get the time interval between the reference time and whatever time it happens to be.
I am attempting to do this the same way I would with NSTimeInterval
, in other words, make a new one and subtract the old one from it:
//Repeat everything from before to make a new wall time.
let newNowInterval = NSDate().timeIntervalSince1970
var newNowStruct = timespec(tv_sec: Int(newNowInterval), tv_nsec: 0)
let newWalltime = dispatch_walltime(& newNowStruct, 0)
//Time math a la NSTimeInterval to find the interval:
let walltimeInterval = newWalltime - referenceWalltime
Will that work?
The short answer is: no. That code will crash.
The better answer is: no, but it can be done, and it's not all that different in the end.
I did some investigating on my own in a Playground and learned some interesting things, and I believe I figured out the right way to do this.
I'm pasting the entirety of my Playground here, so that others can copy-paste it and figure out how to do their own dispatch_time
math.
Comments marked by //********* in the code denote the key things I learned.
import UIKit
import XCPlayground
XCPSetExecutionShouldContinueIndefinitely(continueIndefinitely: true)
public class IntervalMaker {
var referenceWalltime: dispatch_time_t = 0
var newWalltime: dispatch_time_t = 0
var walltimeInterval: dispatch_time_t = 0
func scheduleWalltimeSequence () {
let threeSeconds = Int64(NSEC_PER_SEC) * 3
let now = walltimeNow()
let dispatchTimeInThree = dispatch_time(now, threeSeconds)
let dispatchTimeInSix = dispatch_time(now,
2 * threeSeconds)
setReferenceWalltimeToNow()
dispatch_after(dispatchTimeInThree, dispatch_get_main_queue(),
setNewWalltimeToNow)
dispatch_after(dispatchTimeInSix,
dispatch_get_main_queue(), dispatchBasedOnDispatchMath)
}
func walltimeNow()->dispatch_time_t{
let nowInterval = NSDate().timeIntervalSince1970
var nowStruct = timespec(tv_sec: Int(nowInterval), tv_nsec: 0)
return dispatch_walltime(&nowStruct, 0)
}
func setReferenceWalltimeToNow () {
referenceWalltime = walltimeNow()
}
func setNewWalltimeToNow (){
newWalltime = walltimeNow()
}
func dispatchBasedOnDispatchMath () {
computeInterval() //Should be three seconds
let nineTheWrongWay = referenceWalltime + (walltimeInterval * 3)
let nineTheRightWay = dispatch_time(referenceWalltime,
Int64(walltimeInterval) * 3)
dispatch_after(nineTheWrongWay,
dispatch_get_main_queue(), finalPrintln)
//********** THE ABOVE DOES NOT WORK CORRECTLY - prints 6 seconds later
dispatch_after(nineTheRightWay,
dispatch_get_main_queue(), finalPrintln)
//********** THE ABOVE WORKS CORRECTLY - prints 9 seconds later
}
func finalPrintln () {
let now = walltimeNow()
println("I should be printing nine seconds from reference time.")
println("It's actually \(referenceWalltime - now) nanoseconds after")
}
func computeInterval () {
walltimeInterval = referenceWalltime - newWalltime
//********** dispatch_walltimes actually count backwards, and *CANNOT* be
//********** negative: writing `newWalltime - referenceWalltime` will crash
}
}
let intervaller = IntervalMaker()
intervaller.scheduleWalltimeSequence()
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With