在SwiftUI中使用计时器触发NavigationView更改的正确方法

在SwiftUI中使用计时器触发NavigationView更改的正确方法,swiftui,swiftui-navigationlink,Swiftui,Swiftui Navigationlink,我有一个应用程序,我希望用户能够启动一个定时任务,当时间用完时,导航层次应该弹出并将用户带回来。我有代码~可以工作,但我不喜欢代码的味道。这样做对吗 class SimpleTimerManager: ObservableObject { @Published var elapsedSeconds: Double = 0.0 private(set) var timer = Timer() func start() { timer = Timer.scheduledTi

我有一个应用程序,我希望用户能够启动一个定时任务,当时间用完时,导航层次应该弹出并将用户带回来。我有代码~可以工作,但我不喜欢代码的味道。这样做对吗

class SimpleTimerManager: ObservableObject {
  @Published var elapsedSeconds: Double = 0.0
  private(set) var timer = Timer()
  
  func start() {
    timer = Timer.scheduledTimer(withTimeInterval: 0.01, repeats: true) {_ in
      self.elapsedSeconds += 0.01
    }
  }
  
  func stop() {
    timer.invalidate()
    elapsedSeconds = 0.0
  }
}


struct ContentView: View {
  @ObservedObject var timerManager = SimpleTimerManager()
  
  var body: some View {
    NavigationView {
      NavigationLink(destination: CountDownIntervalView(
        timerManager: timerManager, length: 5.0
      )) {
        Text("Start the timer!")
      }
    }
    .navigationViewStyle(StackNavigationViewStyle())
  }
}


struct CountDownIntervalView: View {
  @ObservedObject var timerManager: SimpleTimerManager
  var length: Double
  @Environment(\.presentationMode) var mode: Binding<PresentationMode>
  var interval: Double {
    let interval = length - self.timerManager.elapsedSeconds
    if interval <= 0 {
      self.mode.wrappedValue.dismiss()
      self.timerManager.stop()
    }
    return interval
  }
    
  var body: some View {
    VStack {
      Text("Time remaining: \(String(format: "%.2f", interval))")
      Button(action: {
        self.mode.wrappedValue.dismiss()
        self.timerManager.stop()
      }) {
        Text("Quit early!")
      }
    }
    .navigationBarBackButtonHidden(true)
    .onAppear(perform: {
      self.timerManager.start()
    })
  }
}
类SimpleTimeManager:ObserveObject{
@已发布变量elapsedSeconds:Double=0.0
专用(设置)变量计时器=计时器()
func start(){
timer=timer.scheduledTimer(withTimeInterval:0.01,repeats:true){in
self.elapsedSeconds+=0.01
}
}
函数停止(){
timer.invalidate()
elapsedSeconds=0.0
}
}
结构ContentView:View{
@ObservedObject var timerManager=SimpleTimerManager()
var body:一些观点{
导航视图{
导航链接(目的地:倒计时IntervalView(
timerManager:timerManager,长度:5.0
)) {
文本(“启动计时器!”)
}
}
.navigationViewStyle(StackNavigationViewStyle())
}
}
结构倒计时IntervalView:视图{
@ObservedObject变量timerManager:SimpleTimerManager
变量长度:双
@环境(\.presentationMode)变量模式:绑定
var间隔:双{
让间隔=长度-self.timermager.elapsedSeconds

如果间隔这里有一个解决方案。使用Xcode 11.4/iOS 13.4测试

struct CountDownIntervalView: View {
  @ObservedObject var timerManager: SimpleTimerManager
  var length: Double
  @Environment(\.presentationMode) var mode: Binding<PresentationMode>

  var interval: Double {
    length - self.timerManager.elapsedSeconds
  }

  var body: some View {
    VStack {
      Text("Time remaining: \(String(format: "%.2f", interval))")
        .onReceive(timerManager.$elapsedSeconds) { _ in
            if self.interval <= 0 {
              self.mode.wrappedValue.dismiss()
              self.timerManager.stop()
            }
        }

    // ... other your code
struct CountDownIntervalView:视图{
@ObservedObject变量timerManager:SimpleTimerManager
变量长度:双
@环境(\.presentationMode)变量模式:绑定
var间隔:双{
长度-self.timermager.elapsedSeconds
}
var body:一些观点{
VStack{
文本(“剩余时间:\(字符串(格式:%.2f”,间隔)))
.onReceive(timerManager.$elapsedSeconds){in

如果self.interval引人入胜-我没有意识到我应该把
elapsedSeconds
当作一个绑定在那里!我接受了这个解决方案,因为我认为你支持在
文本
上附加pop代码的想法,而不是视图中的其他地方。这对我来说仍然有点可疑,但我愿意相信这是SwiftUI的最佳实践。
struct CountDownIntervalView: View {
  @ObservedObject var timerManager: SimpleTimerManager
  var length: Double
  @Environment(\.presentationMode) var mode: Binding<PresentationMode>

  var interval: Double {
    length - self.timerManager.elapsedSeconds
  }

  var body: some View {
    VStack {
      Text("Time remaining: \(String(format: "%.2f", interval))")
        .onReceive(timerManager.$elapsedSeconds) { _ in
            if self.interval <= 0 {
              self.mode.wrappedValue.dismiss()
              self.timerManager.stop()
            }
        }

    // ... other your code