代码之家  ›  专栏  ›  技术社区  ›  bogen

如何在0.3秒后,在给定次数内执行动作?

  •  7
  • bogen  · 技术社区  · 9 年前
    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执行了几乎一秒钟后,控制台开始表现出奇怪的样子,同时显示两行和两行打印行

    9.0 - 9.88806998729706 : 30
    9.3 - 9.88832598924637 : 31
    

    有没有办法 XCTest 更接近于“在正确的时间”完成请求?比如,9秒后应该完成的请求,9.88秒后却没有完成。。

    2 回复  |  直到 9 年前
        1
  •  2
  •   Bernem    9 年前

    不确定您是否已开始使用分派,但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所需的时间),不会漂移或聚集在一起。

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

        2
  •  1
  •   Sulthan    9 年前

    使用 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)
        }
    }
    

    请注意,该方法实际上执行了多次,您必须在内部检查是否经过了足够的时间。