You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Swift iOS:实现串行函数执行,解决多函数并行执行问题

解决方案:用Completion回调+递归实现顺序执行与重复

你的问题核心在于Timer的异步特性——Timer.scheduledTimer是把任务调度到RunLoop里异步执行的,不会阻塞当前代码的运行。所以你调用timer1()之后,代码会立刻跳到timer2()执行,直接把背景色改成绿色,而且两个Timer还会互相覆盖全局的timer变量,完全打乱了预期逻辑。

这里推荐用Completion Handler(完成回调)+递归的方案,既保证步骤严格顺序执行,又能轻松扩展后续需求,代码也更易维护。

优化后的完整代码

import UIKit

class ViewController: UIViewController {
    // 把流程步骤抽成可配置的结构体,方便后续扩展修改
    struct SequenceStep {
        let color: UIColor
        let duration: Int
        // 扩展:支持每一秒的自定义动作(比如第n秒播放音效)
        let onTick: ((Int) -> Void)?
        
        init(color: UIColor, duration: Int, onTick: ((Int) -> Void)? = nil) {
            self.color = color
            self.duration = duration
            self.onTick = onTick
        }
    }
    
    // 颜色定义
    private let redColor = UIColor(red: 255/255.0, green: 0/255.0, blue: 0/255.0, alpha: 1.0)
    private let greenColor = UIColor(red: 0/255.0, green: 255/255.0, blue: 0/255.0, alpha: 1.0)
    
    // 配置完整流程:后续加步骤直接在这里加就行
    private let fullSequence: [SequenceStep] = [
        SequenceStep(color: .red, duration: 30, onTick: { remainingSeconds in
            // 示例:第4秒播放音效(30-4=26,剩余26秒时触发)
            if remainingSeconds == 26 {
                print("播放提示音效!")
                // 这里添加播放音效的代码即可
            }
        }),
        SequenceStep(color: .green, duration: 10)
    ]
    
    private var currentTimer: Timer?
    private var repeatCount = 0
    private let totalRepeatTimes = 3 // 总共重复3次
    
    @IBOutlet weak var startButton: UIButton!
    
    @IBAction func startSequence(_ sender: Any) {
        startButton.isHidden = true
        repeatCount = 0
        startNextRepeatCycle()
    }
    
    // 启动一轮完整的流程循环
    private func startNextRepeatCycle() {
        guard repeatCount < totalRepeatTimes else {
            // 所有循环完成,可添加结束逻辑
            print("全部流程执行完毕")
            startButton.isHidden = false // 可选:重新显示开始按钮
            return
        }
        repeatCount += 1
        executeStep(atIndex: 0)
    }
    
    // 按顺序执行单个步骤,完成后自动触发下一个
    private func executeStep(atIndex index: Int) {
        guard index < fullSequence.count else {
            // 一轮步骤完成,启动下一次循环
            startNextRepeatCycle()
            return
        }
        
        let step = fullSequence[index]
        view.backgroundColor = step.color
        
        var remainingSeconds = step.duration
        currentTimer?.invalidate() // 先销毁之前的定时器,避免冲突
        currentTimer = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { [weak self] timer in
            guard let self = self else {
                timer.invalidate()
                return
            }
            
            // 执行当前步骤的自定义tick动作
            step.onTick?(remainingSeconds)
            
            remainingSeconds -= 1
            if remainingSeconds < 0 {
                timer.invalidate()
                self.currentTimer = nil
                // 执行下一个步骤
                self.executeStep(atIndex: index + 1)
            }
        }
    }
}

这个方案的优势

  • 严格顺序执行:每个步骤完全完成后才会触发下一个,彻底解决同时执行的问题。
  • 超强扩展性:
    • 加新步骤:直接在fullSequence数组里添加新的SequenceStep实例。
    • 加中间动作:在SequenceStep的onTick回调里判断剩余秒数即可实现(比如第4秒播放音效)。
    • 修改时长/颜色:直接修改SequenceStep的参数,不用动核心执行逻辑。
  • 清晰的重复逻辑:用递归的startNextRepeatCycle控制重复次数,逻辑一目了然。
  • 避免全局变量混乱:把定时器和计数改成实例变量,防止被意外覆盖。

额外注意点

  • 用[weak self]避免循环引用,防止内存泄漏。
  • 每次启动新定时器前先销毁旧的,避免多个定时器同时运行。
  • 可以把totalRepeatTimes、fullSequence做成可配置的变量,支持动态修改。

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 03:42:15