【问题标题】:mach_wait_until() Strange Behavior on iPadmach_wait_until() iPad 上的奇怪行为
【发布时间】:2018-05-05 01:20:22
【问题描述】:

我创建了一个简单的项目来测试mach_wait_until() 的功能。此代码为我提供了 1 秒延迟有多精确的准确打印输出。在 iOS 模拟器和我的 iPad Air 2 上,控制台打印输出几乎相同且极其精确。但是,在我的 iPad 上,有一个巨大的延迟,同样的 1 秒延迟大约需要 100 秒!更奇怪的是,控制台中的打印输出说它只需要 1 秒(具有极低的抖动和/或延迟)。

这怎么可能?使用mach_wait_until()时,我需要为物理iOS设备做一些时间转换吗?

class ViewController: UIViewController {

    override func viewDidLoad() {
      super.viewDidLoad()
      playNoteTest()
    }

    var start = mach_absolute_time()
    var end = mach_absolute_time()

    func playNoteTest() {
      let when = mach_absolute_time() + 1000000000

      self.start = mach_absolute_time()
      mach_wait_until(when)
      self.end = mach_absolute_time()
      let timeDelta = (self.end - self.start)
      let newTimeDelta = Double(timeDelta) / 1000000000.0
      print("Delta Time = \(newTimeDelta)")

      playNoteTest()
    }
}

【问题讨论】:

    标签: ios swift timer ios-simulator


    【解决方案1】:

    mach_absolute_time 单位取决于 CPU。您需要乘以特定于设备的常量才能获得实际单位。 Apple 的 Tech Q&A 对此进行了讨论。

    这里有一些演示这个想法的操场代码:

    import PlaygroundSupport
    import Foundation
    
    PlaygroundPage.current.needsIndefiniteExecution = true
    
    class TimeBase {
        static let NANOS_PER_USEC: UInt64 = 1000
        static let NANOS_PER_MILLISEC: UInt64 = 1000 * NANOS_PER_USEC
        static let NANOS_PER_SEC: UInt64 = 1000 * NANOS_PER_MILLISEC
    
        static var timebaseInfo: mach_timebase_info! = {
            var tb = mach_timebase_info(numer: 0, denom: 0)
            let status = mach_timebase_info(&tb)
            if status == KERN_SUCCESS {
                return tb
            } else {
                return nil
            }
        }()
    
        static func toNanos(abs:UInt64) -> UInt64 {
            return (abs * UInt64(timebaseInfo.numer)) / UInt64(timebaseInfo.denom)      
        }
    
        static func toAbs(nanos:UInt64) -> UInt64 {
            return (nanos * UInt64(timebaseInfo.denom)) / UInt64(timebaseInfo.numer)
        }
    
    }
    
    let duration = TimeBase.toAbs(nanos: 10 * TimeBase.NANOS_PER_SEC)
    
    DispatchQueue.global(qos: .userInitiated).async {
    
        print("Start")
        let start = mach_absolute_time()
        mach_wait_until(start+duration)
        let stop = mach_absolute_time()
    
        let elapsed = stop-start
        let elapsedNanos = TimeBase.toNanos(abs: elapsed)
        let elapsedSecs = elapsedNanos/TimeBase.NANOS_PER_SEC
        print("Elapsed nanoseconds = \(elapsedNanos)")
        print("Elapsed seconds = \(elapsedSecs)")
    
    }
    

    【讨论】:

    • 谢谢!我还有一个相关的问题......我上面的代码给出了非常准确的时间重复,但是,它基本上让我无法使用我的应用程序的所有功能。 CPU 不会在模拟器中进行诊断。像mach_wait_until() 这样的方法是否只需要放在一个单独的线程上来解决这个问题?如果是这样,您能否在答案中添加示例代码来解决这方面的问题?还是您认为我应该为此创建一个新问题?
    • 是的,mach_wait_until 阻塞了当前线程。在主线程/队列上运行它是个坏主意™
    • 太棒了!我想是时候让我学习如何多线程了......如果有一种简单的方法可以将它添加到你的示例中,我将不胜感激
    • 查看更新以获取将工作分派到后台队列的示例
    • 感谢您添加DispatchQueue 代码以便清楚起见。不幸的是,这个答案还没有解决我的问题......该代码的工作原理与我上面在模拟器上更简单的“不正确”代码一样好。使用我上面的代码,我的物理 iPad 上的时间太慢了。现在我已经用Apple指定的“设备特定常量”替换了它,时间太快了......在我的代码中,它在15-60ms延迟/循环!而不是预期的 1 秒(我在“持续时间”中规定,您已在 10(秒)处列出)。
    猜你喜欢
    • 2020-12-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-06
    • 2011-11-25
    • 2015-11-21
    • 1970-01-01
    • 2012-03-30
    相关资源
    最近更新 更多