2016-04-18 34 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) 
    } 
} 

請注意,該方法實際上是多次執行的,並且在內部您必須檢查是否有足夠的時間流逝。

相關問題