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

iOS Swift:如何用单个函数在同一屏幕显示多个计时器

iOS多Spot独立倒计时实现方案

不要为每个Spot单独创建Timer,这既浪费资源又不好管理。推荐用单个全局Timer统一驱动所有倒计时,配合数据模型维护每个Spot的独立状态,具体实现步骤如下:

1. 定义Spot倒计时数据模型

创建模型类存储每个Spot的倒计时信息与对应UI组件:

class SpotTimerModel {
    let spotId: String // 唯一标识Spot,避免混淆
    var remainingSeconds: Int
    weak var displayLabel: UILabel? // 关联显示倒计时的Label,用weak避免循环引用
    
    init(spotId: String, initialSeconds: Int, displayLabel: UILabel) {
        self.spotId = spotId
        self.remainingSeconds = initialSeconds
        self.displayLabel = displayLabel
    }
}

2. 管理所有活跃Spot计时器

在ViewController中维护数组管理倒计时中的Spot,同时保留全局Timer引用:

class YourViewController: UIViewController {
    private var activeSpotTimers: [SpotTimerModel] = []
    private var updateTimer: Timer?
    
    // ... 其他业务代码
}

3. 实现Spot解锁逻辑

用户解锁Spot时,创建对应模型实例并加入数组,按需启动全局Timer:

func unlockSpot(withId spotId: String, displayLabel: UILabel) {
    // 避免重复添加同一Spot的计时器
    guard !activeSpotTimers.contains(where: { $0.spotId == spotId }) else { return }
    
    let spotTimer = SpotTimerModel(spotId: spotId, initialSeconds: 60, displayLabel: displayLabel)
    activeSpotTimers.append(spotTimer)
    
    // 更新初始显示
    updateDisplay(for: spotTimer)
    
    // Timer未启动则启动
    if updateTimer == nil {
        updateTimer = Timer.scheduledTimer(timeInterval: 1.0, target: self, selector: #selector(updateAllCounters), userInfo: nil, repeats: true)
    }
}

4. 统一更新所有倒计时

实现全局Timer回调,遍历更新所有活跃Spot的倒计时状态与UI:

@objc private func updateAllCounters() {
    // 倒序遍历,避免删除元素时索引混乱
    for index in (0..<activeSpotTimers.count).reversed() {
        let spotTimer = activeSpotTimers[index]
        
        if spotTimer.remainingSeconds > 0 {
            spotTimer.remainingSeconds -= 1
            updateDisplay(for: spotTimer)
        } else {
            // 倒计时结束,移除Spot并处理UI
            spotTimer.displayLabel?.text = "已完成"
            activeSpotTimers.remove(at: index)
            
            // 无活跃Spot时停止Timer节省资源
            if activeSpotTimers.isEmpty {
                updateTimer?.invalidate()
                updateTimer = nil
            }
        }
    }
}

// 封装UI更新逻辑,复用性更强
private func updateDisplay(for spotTimer: SpotTimerModel) {
    guard let label = spotTimer.displayLabel else { return }
    
    let minutes = spotTimer.remainingSeconds / 60
    let seconds = spotTimer.remainingSeconds % 60
    // 格式化显示,不足10秒补0,比如"0:30"或"1:05"
    label.text = String(format: "%d:%02d", minutes, seconds)
}

5. 生命周期与内存管理

页面消失时停止Timer并清空数组,避免内存泄漏:

override func viewWillDisappear(_ animated: Bool) {
    super.viewWillDisappear(animated)
    updateTimer?.invalidate()
    updateTimer = nil
    activeSpotTimers.removeAll()
}

关键说明

  • 单个Timer驱动所有倒计时,性能更优且易管理
  • 用唯一ID标识Spot,防止重复添加计时器
  • weak引用UI组件,规避循环引用风险
  • 倒序遍历处理删除操作,避免索引越界问题

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 18:15:48