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
相关产品推荐
相关产品推荐

