Swift:我可以添加和减去`dispatch_time_t` 变量吗?

Le *_*ced 5 time grand-central-dispatch ios swift

我需要在 iOS 中用 Swift 做一些时间数学。

我必须使用dispatch_walltime. 我希望这可以被视为公理。就时间数学而言,我想我可能会得到“只是使用NSDate”的回应,但请相信:我一定会dispatch_walltime。

现在,很明显为什么有人会建议NSDate,因为当您使用NSTimeIntervalandNSDate和那些好东西时,制作自定义时间戳并比较它们并进行各种时间数学计算非常容易。

但我必须使用dispatch_time_t, 并且专门dispatch_walltime像这样创建:

//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)
Run Code Online (Sandbox Code Playgroud)

稍后我需要以各种方式使用该参考时间。例如,我需要获取参考时间和它发生的任何时间之间的时间间隔。

我正在尝试以与 相同的方式执行此操作NSTimeInterval,换句话说,创建一个新的并从中减去旧的:

//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
Run Code Online (Sandbox Code Playgroud)

那行得通吗?

Le *_*ced 2

最简洁的答案是不。该代码将会崩溃。

更好的答案是:不,但是可以做到,而且最终并没有什么不同。

我在操场上自己做了一些调查,学到了一些有趣的东西,我相信我找到了正确的方法。

我将整个 Playground 粘贴到此处,以便其他人可以复制粘贴它并弄清楚如何进行自己的dispatch_time数学运算。

代码中用 //********* 标记的注释表示我学到的关键内容。

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()
Run Code Online (Sandbox Code Playgroud)