Vision Pro真机Timer.autoconnect失效,模拟器正常问题求助
Vision Pro真机上Timer.publish计时器不触发问题
我开发的倒计时视图在Vision Pro模拟器中运行正常,但真机上无法工作。需求是从指定数值开始倒计时,结束后重置初始值并调用完成回调。
核心代码片段:
启动计时器:
let timer = Timer.publish(every: 1, on: .main, in: .common).autoconnect()
每秒执行逻辑:
Text("\(secondsRemaining)") .font(.extraLargeTitle) .contentTransition(.numericText()) .onReceive(timer) { _ in // 模拟器中触发,真机不触发 }
更新:完整代码如下
struct CountDownView: View { @Environment(\.scenePhase) var scenePhase @State private var isActive = true let duration: Int @State private var secondsRemaining: Int @Binding var isCountingDown: Bool var onEnded: (() -> Void)? let timer = Timer.publish(every: 1, on: .main, in: .common).autoconnect() init(duration: Int, onEnded: (() -> Void)?, start: Binding<Bool>) { self.onEnded = onEnded self.duration = duration self._isCountingDown = start self._secondsRemaining = State(initialValue: duration) } var body: some View { Text(secondsRemaining, format: .number) .font(.extraLargeTitle) .contentTransition(.numericText()) .onChange(of: scenePhase) { if scenePhase == .active { isActive = true } else { isActive = false } } .onReceive(timer) { _ in if isCountingDown { if secondsRemaining > 0 { withAnimation { secondsRemaining -= 1 } } else { self.onTerminated() } } } } func onTerminated() { timer.upstream.connect().cancel() self.secondsRemaining = duration onEnded?() } }
问题原因
- Timer.publish生命周期不可控:
autoconnect()会自动连接计时器,但Vision Pro真机的系统资源管控更严格,当视图隐藏或场景切换到非活跃状态时,计时器会被暂停,模拟器因资源限制宽松不会触发该逻辑。 - 场景状态未关联计时器逻辑:代码中监听了
scenePhase但未用isActive控制计时器启停,真机上App后台切换后无法恢复计时。 - 计时器取消逻辑错误:
timer.upstream.connect().cancel()无法正确重启计时器,因为timer是结构体属性,取消后不会自动重新连接,导致后续无法触发。
解决方案
改用手动管理的计时器,结合场景状态和绑定值控制启停:
struct CountDownView: View { @Environment(\.scenePhase) var scenePhase @State private var timerCancellable: AnyCancellable? let duration: Int @State private var secondsRemaining: Int @Binding var isCountingDown: Bool var onEnded: (() -> Void)? init(duration: Int, onEnded: (() -> Void)?, start: Binding<Bool>) { self.onEnded = onEnded self.duration = duration self._isCountingDown = start self._secondsRemaining = State(initialValue: duration) } var body: some View { Text(secondsRemaining, format: .number) .font(.extraLargeTitle) .contentTransition(.numericText()) .onChange(of: isCountingDown) { newValue in newValue ? startTimer() : stopTimer() } .onChange(of: scenePhase) { newPhase in if newPhase == .active, isCountingDown { startTimer() } else { stopTimer() } } .onAppear { if isCountingDown { startTimer() } } } private func startTimer() { stopTimer() // 避免重复创建计时器 timerCancellable = Timer.publish(every: 1, on: .main, in: .common) .autoconnect() .sink { [weak self] _ in guard let self = self, self.isCountingDown else { return } if self.secondsRemaining > 0 { withAnimation { self.secondsRemaining -= 1 } } else { self.onTerminated() } } } private func stopTimer() { timerCancellable?.cancel() timerCancellable = nil } private func onTerminated() { stopTimer() secondsRemaining = duration onEnded?() // 如需自动重启,可在此设置isCountingDown = true } }
关键修改点
- 用
AnyCancellable手动管理计时器生命周期,避免autoconnect()的不可控问题 - 监听
isCountingDown绑定值变化,触发计时器启停 - 结合
scenePhase,在场景激活时重启计时器,非活跃时停止,适配真机系统资源管理 - 取消计时器时直接释放
timerCancellable,确保可重新创建新计时器
内容的提问来源于stack exchange,提问作者Magnus T
相关产品推荐
相关产品推荐

