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

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?()
      }
}

问题原因

  1. Timer.publish生命周期不可控:autoconnect()会自动连接计时器,但Vision Pro真机的系统资源管控更严格,当视图隐藏或场景切换到非活跃状态时,计时器会被暂停,模拟器因资源限制宽松不会触发该逻辑。
  2. 场景状态未关联计时器逻辑:代码中监听了scenePhase但未用isActive控制计时器启停,真机上App后台切换后无法恢复计时。
  3. 计时器取消逻辑错误: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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 12:15:14