Вот структура, которую я написал для преобразования NSTimeInterval в 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 (с моим WallTimeKeeper в папке Sources):
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)
... так что не только dotrueIfActionFiredPunctually()
всегда возвращает false, но и значение difference
, предназначенное для измерения разницы между временем срабатывания обратного вызова и временем, когда он должен был должен срабатывать, что в случае успешного результата должен быть очень близок к 0 и уж точно меньше 1 — вместо этого получается почти то же самое, что и количество времени, в течение которого обратный вызов должен был ждать срабатывания.
Подводя итог: определяется количество времени ожидания, и действие запускается по истечении этого времени. Когда действие запускается, оно создает временную метку момента запуска. Когда метка времени сравнивается со значением, которым она должна быть, вместо того, чтобы приближаться к нулю, мы приближаемся к количеству времени, которое мы должны были ждать.
Другими словами, создается впечатление, что действие, переданное dispatch_after
, срабатывает немедленно, чего абсолютно не должно быть!
Это что-то не так с Playgrounds или с моим кодом?
EDIT: Это код. Запуск того же кода внутри живого приложения дает тот же результат. Что я делаю не так?
abs(difference) < 0
никогда не будет правдой :) - person Martin R   schedule 25.07.2015abs(difference) < 1
. Результаты те же самые, за исключением того, что на этот раз по правильным причинам. - Ле Мот Сок - person Le Mot Juiced   schedule 25.07.2015XCPSetExecutionShouldContinueIndefinitely(continueIndefinitely: true)
с целью тестирования вызовов асинхронных функций. К сожалению, в этом случае его активация никак не влияет на результат Playground. Дело в том, что диспетчеризация срабатывает мгновенно, поэтому бесконечное продолжение выполнения не имеет никакого эффекта. - person Le Mot Juiced   schedule 25.07.2015