这是我编写的用于将NSTimeInterval转换为基于walltime的dispatch_time_t的结构:
public struct WallTimeKeeper {
public static func walltimeFrom(spec: timespec)->dispatch_time_t {
var mutableSpec = spec
let wallTime = dispatch_walltime(&mutableSpec, 0)
return wallTime
}
public static func timeStructFrom(interval: NSTimeInterval)->timespec {
let nowWholeSecsFloor = floor(interval)
let nowNanosOnly = interval - nowWholeSecsFloor
let nowNanosFloor = floor(nowNanosOnly * Double(NSEC_PER_SEC))
println("walltimekeeper: DEBUG: nowNanosFloor: \(nowNanosFloor)")
var thisStruct = timespec(tv_sec: Int(nowWholeSecsFloor),
tv_nsec: Int(nowNanosFloor))
return thisStruct
}
}
我一直试图在游乐场测试它的准确性,但我的结果令我感到困惑。
这是我的Playground中的代码(在Sources文件夹中使用我的WallTimeKeeper):
var stop = false
var callbackInterval: NSTimeInterval?
var intendedTime: NSDate?
var intendedAction: ()->() = {}
func testDispatchingIn(thisManySeconds: NSTimeInterval){
intendedTime = NSDate(timeIntervalSinceNow: thisManySeconds)
intendedAction = stopAndGetDate
dispatchActionAtDate()
loopUntilAfterIntendedTime()
let success = trueIfActionFiredPunctually() //always returns false
}
func dispatchActionAtDate(){
let timeToAct = dateAsDispatch(intendedTime!)
let now = dateAsDispatch(NSDate())
/*****************
NOTE: if you run this code in a Playground, comparing the above two
values will show that WallTimeKeeper is returning times the
correct number of seconds apart.
******************/
dispatch_after(timeToAct, dispatch_get_main_queue(), intendedAction)
}
func loopUntilAfterIntendedTime() {
let afterIntendedTime = intendedTime!.dateByAddingTimeInterval(1)
while stop == false && intendedTime?.timeIntervalSinceNow > 0 {
NSRunLoop.currentRunLoop().runMode(NSDefaultRunLoopMode,
beforeDate: afterIntendedTime)
}
}
func trueIfActionFiredPunctually()->Bool{
let intendedInterval = intendedTime?.timeIntervalSinceReferenceDate
let difference = intendedInterval! - callbackInterval!
let trueIfHappenedWithinOneSecondOfIntendedTime = abs(difference) < 1
return trueIfHappenedWithinOneSecondOfIntendedTime
}
func dateAsDispatch(date: NSDate)->dispatch_time_t{
let intendedAsInterval = date.timeIntervalSinceReferenceDate
let intendedAsStruct = WallTimeKeeper.timeStructFrom(intendedAsInterval)
let intendedAsDispatch = WallTimeKeeper.walltimeFrom(intendedAsStruct)
return intendedAsDispatch
}
func stopAndGetDate() {
callbackInterval = NSDate().timeIntervalSinceReferenceDate
stop = true
}
testDispatchingIn(3)
...所以trueIfActionFiredPunctually()
不仅总是返回false,而且difference
值 - 用于衡量回调触发时间和假定时间之间的差异< / em> to fire - 在一个成功的结果中应该真的接近0,当然低于1 - 而不是几乎完全相同的回调应该等待的时间他们开火了。
总结:定义了等待的时间量,并设置了在该时间量后触发的操作。当动作触发时,它会创建一个触发时刻的时间戳。当时间戳与它应该的值进行比较时,我们接近我们应该等待的时间,而不是接近于零。
换句话说,似乎传递给dispatch_after
的动作立即被触发,绝对不应该这样做!
Playgrounds有问题或我的代码有问题吗?
修改 这是代码。在实时应用程序中运行相同的代码会产生相同的结果。我做错了什么?
答案 0 :(得分:1)
我明白了。这是一个头脑风暴。如果有人遇到同样的问题,我会留下它。
我正在使用NSDate().timeIntervalSinceReferenceDate
设置我的时间。
Walltimes需要NSDate().timeIntervalSince1970
!
dispatch_after任务全部立即被解雇,因为他们认为这些任务是在四十多年前安排的!
将所有内容更改为NSDate().timeIntervalSince1970
会使其完美运行。
道德:除非你确定你的参考日期是1970年,否则不要使用walltimes!