You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Swift中优化循环迭代暂停:替代sleep实现60秒间隔

嘿,我明白你为啥觉得用sleep循环不太靠谱——这种方式不仅容易阻塞线程(要是在UI应用里用,界面直接卡死),要是播放声音这类操作占了点时间,累计下来的时间误差会越来越大,而且想中途取消循环都特别麻烦。给你几个更优的实现思路,看哪种适合你的场景:

方案1:用定时器(适合UI应用,时间更准确)

如果是iOS/macOS这类有UI的场景,用Timer绝对是更好的选择。它不会阻塞主线程,而且会基于系统时钟调整触发时间,误差比sleep小很多。

比如Swift里可以这么写:

var currentCount = 0
let totalCycles = 60

// 创建每秒触发一次的定时器
let timer = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { timer in
    // 检查当前计数是否在需要播放声音的列表里
    if arrayOfOptions.contains(currentCount) {
        // 播放声音的逻辑
        playSound()
    }
    
    currentCount += 1
    // 达到次数后停止定时器
    if currentCount > totalCycles {
        timer.invalidate()
    }
}
方案2:用调度队列的延迟执行(适合后台任务)

如果你的逻辑是在后台跑的,不想用Timer,可以用DispatchQueueasyncAfter做递归调用。这种方式同样不会阻塞线程,而且能灵活控制执行队列。

示例代码:

var currentCount = 0
let totalCycles = 60
// 用后台队列执行,避免影响UI
let backgroundQueue = DispatchQueue.global(qos: .background)

func runCycle() {
    // 先判断是否已经完成所有循环
    guard currentCount <= totalCycles else { return }
    
    // 检查是否需要播放声音
    if arrayOfOptions.contains(currentCount) {
        // 要是播放声音需要主线程,记得切换回去
        DispatchQueue.main.async {
            playSound()
        }
    }
    
    currentCount += 1
    // 延迟1秒后执行下一次循环
    backgroundQueue.asyncAfter(deadline: .now() + 1.0) {
        runCycle()
    }
}

// 启动循环
runCycle()
如果你实际需求是「每次迭代间隔60秒」

哦对了,要是你说的“每次迭代间隔60秒”是指每60秒执行一次任务(而不是60次每秒一次的循环),那只需要把上面代码里的时间间隔改成60.0就行,比如Timer的withTimeInterval: 60.0,或者asyncAfter.now() + 60.0

为啥这些方案比sleep好?

  • 非阻塞:不会卡住UI或者其他线程的任务,用户体验更流畅
  • 时间更准:定时器和调度队列的延迟都是基于系统时钟计算的,就算播放声音花了时间,下一次执行的间隔还是准确的
  • 可灵活取消:Timer可以调用invalidate()停止,递归的方式也可以加个标志位随时终止,不像sleep期间根本没法响应取消信号

内容的提问来源于stack exchange,提问作者purplePanda

火山引擎 最新活动