2016-04-18 48 views
7
let expecation = expectationWithDescription("do tasks") 
for i in 0...40 { 

    let afterTiming = 0.3 * Double(i) 
    let startTime = CFAbsoluteTimeGetCurrent() 

    let delayTime = dispatch_time(DISPATCH_TIME_NOW, Int64(afterTiming * Double(NSEC_PER_SEC))) 

    dispatch_after(delayTime, dispatch_get_main_queue()) { 
     let timeElapsed = CFAbsoluteTimeGetCurrent() - startTime 
     print("\(afterTiming) - \(timeElapsed) : \(i)") 
    } 
} 

waitForExpectationWithTimeout(14) 

30后执行它几乎是第二关,和控制台开始显示两个和两个打印线怪怪的同时如何在0.3秒后精确地执行一个动作达到给定的次数?

9.0 - 9.88806998729706 : 30 
9.3 - 9.88832598924637 : 31 

有没有办法为XCTest更贴近实际做的请求“在正确的时间“?喜欢把自己不被9.88秒后9中那样秒钟后应该做的请求..

+1

我删除了'XCTest'标签,因为它没有任何与XCTests相关的特定内容。这只是巧合,你需要这个测试。虽然...我很想看看你真的想要这样测试(然后再添加标签)。 – nhgrif

+0

@nhgrif重要的是XCTest被提及,因为它实际上调用了waitForExpectationsWithTimeout() - 我不确定这是否可以用于例如在测试中阻塞主线程 – hakonbogen

+1

如果您觉得提及'XCTest'很重要,那么您*真的*需要提供您正在尝试为上下文运行的测试。就目前来看,这是一个[XY问题](http://meta.stackexchange.com/q/66377/244435)。 – nhgrif

回答

2

不确定您是否设置了使用分派,但NSTimer在我的测试中表现得更准确。下面是一些示例代码来执行的操作numOfTimes次

var iterationNumber = 0 
var startTime = CFAbsoluteTimeGetCurrent() 
let numOfTimes = 30 

// Start a repeating timer that calls 'action' every 0.3 seconds 
var timer = NSTimer.scheduledTimerWithTimeInterval(0.3, target: self, selector: #selector(ViewController.action), userInfo: nil, repeats: true) 

func action() { 
    // Print relevant information 
    let timeElapsed = CFAbsoluteTimeGetCurrent() - startTime 
    print("\(Double(iterationNumber+1) * 0.3) - \(timeElapsed) : \(CFAbsoluteTimeGetCurrent())") 

    // Increment iteration number and check if we've hit the limit 
    iterationNumber += 1 
    if iterationNumber > numOfTimes { 
     timer.invalidate() 
    } 
} 

一些程序的输出:

7.8 - 7.80285203456879 : 25 
8.1 - 8.10285001993179 : 26 
8.4 - 8.40283703804016 : 27 
8.7 - 8.70284104347229 : 28 
9.0 - 9.00275802612305 : 29 
9.3 - 9.3028250336647 : 30 

它停留的预期时间在几毫秒内(我假设是时候它需要调用CFAbsoluteTimeGetCurrent)并且不会漂移或聚集在一起。

这种方法的一个缺点是它没有像在代码中一样预先安排每个动作,尽管我不确定这对您是否重要。

+1

'NSTimer'记录的精度为50-100毫秒,请参阅http://stackoverflow.com/questions/9737877/how-to - 准确定时器在ios中,所以这可能是足够好的。 – Sulthan

+0

很高兴知道。谢谢! – Bernem

+0

另外,'NSTimer'提供了一个公差值,允许您指定系统按时执行任务的严格程度。虽然默认值为0,即使实际精度稍微偏低,“NSTimer”会自动调度下一个启动日期,而不管上次启动的实际时间是在何时发生,以防止拖动。 –

1

使用CADisplayLink,高精度计时器

(不漂亮的代码,就砍死在一起快)

var displayLink: CADisplayLink? 
var startTime: CFAbsoluteTime = 0 
var nextTime: CFAbsoluteTime = 0 
var index: Int = 0 

func testIncrement() { 
    self.startTime = CFAbsoluteTimeGetCurrent() 
    self.nextTime = self.startTime 

    displayLink = CADisplayLink(target: self, selector: #selector(execute)) 
    displayLink?.addToRunLoop(NSRunLoop.mainRunLoop(), forMode: NSRunLoopCommonModes) 

    let expectation = expectationWithDescription("test") 

    self.waitForExpectationsWithTimeout(20.0, handler: nil) 
} 

func execute() { 
    let currentTime = CFAbsoluteTimeGetCurrent() 

    if (currentTime - nextTime < 0) { 
     return 
    } 

    let timeElapsed = currentTime - startTime 

    print("\(timeElapsed) : \(index)") 

    index += 1 
    nextTime = startTime + 0.3 * CFAbsoluteTime(index) 

    if (index > 30) { 
     displayLink?.removeFromRunLoop(NSRunLoop.mainRunLoop(), forMode: NSRunLoopCommonModes) 
    } 
} 

请注意,该方法实际上是多次执行的,并且在内部您必须检查是否有足够的时间流逝。

相关问题