Swift UI中EMOM间隔计时器整点发声异常问题求助
问题解决:EMOM计时器整点分钟提示音修复
问题分析
当前代码存在两个核心问题:
- 独立的
soundTimer采用固定60秒重复触发逻辑,暂停恢复后会从暂停时刻重新计算间隔,导致提示音无法落在剩余时间的整点分钟节点(如9:00、8:00这类整分点)。 - 计时基础逻辑错误:
secondsLeft直接存储分钟数,却在计时器中每秒减1,导致实际计时时长远短于设置值。
解决方案
- 修正计时基础逻辑:将设置的分钟数转换为秒数存储,确保计时时长与预期一致。
- 替换固定间隔定时器:移除独立的
soundTimer,在主计时器的每秒回调中检查剩余时间是否为60的整数倍(即整点分钟节点),满足条件时播放提示音,确保无论暂停恢复多少次,提示音都只在整分点触发。
修改后的完整代码
import Foundation import SwiftUI import AVFAudio // 补充原代码缺失的枚举定义 enum EMOMTimerMode { case initial case running case paused } class EmomTimerModes: ObservableObject { @Published var timerMode: EMOMTimerMode = .initial // 存储总秒数,初始值基于用户设置的分钟数转换 @Published var secondsLeft = UserDefaults.standard.integer(forKey: "timerLength") * 60 var timer = Timer() func setTimerLength(minutes: Int) { let defaults = UserDefaults.standard defaults.set(minutes, forKey: "timerLength") // 将分钟转换为秒存储,修正计时逻辑 secondsLeft = minutes * 60 } func start() { timerMode = .running timer = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true, block: { timer in // 触发整点分钟提示音:剩余时间为60的整数倍且大于0 if self.secondsLeft > 0 && self.secondsLeft % 60 == 0 { playSound(sound: "race-start", type: "wav") } // 剩余3秒内的提示音逻辑保持不变 if self.secondsLeft > 0 && self.secondsLeft <= 3 { playSound(sound: "race-beep", type: "wav") } if self.secondsLeft == 1 { playSound(sound: "race-start", type: "wav") self.timer.invalidate() self.reset() } guard self.secondsLeft > 0 else { self.timer.invalidate() return } self.secondsLeft -= 1 }) } func reset() { self.timerMode = .initial let savedMinutes = UserDefaults.standard.integer(forKey: "timerLength") // 重置时转换为秒数 self.secondsLeft = savedMinutes * 60 timer.invalidate() } func pause() { self.timerMode = .paused timer.invalidate() } } // 补充原代码缺失的音效播放函数 func playSound(sound: String, type: String) { guard let path = Bundle.main.path(forResource: sound, ofType: type) else { return } let url = URL(fileURLWithPath: path) do { let player = try AVAudioPlayer(contentsOf: url) player.play() } catch let error { print("播放音效失败:\(error.localizedDescription)") } }
关键修改说明
- 计时逻辑修正:所有涉及
secondsLeft的操作都将分钟转换为秒,确保计时时长与设置一致。 - 整点提示音触发:通过
secondsLeft % 60 == 0判断剩余时间是否为整分点,每次进入整分点时仅触发一次提示音,暂停恢复后,主计时器会自动检测下一个整分点。 - 移除冗余定时器:删除独立的
soundTimer,减少资源占用,同时避免定时器不同步的问题。
内容的提问来源于stack exchange,提问作者SH21
相关产品推荐
相关产品推荐

