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

时间:2020-07-20 11:18:50

标签: swiftui swiftui-navigationlink

我有一个应用程序,希望用户能够启动定时任务,并且当时间用完时,导航层次结构应该会弹出并将用户带回。我有可以运行的代码,但是我不喜欢代码的味道。这是处理类似问题的正确方法吗?

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

我有一个自定义的后退按钮,我想保留它。我主要担心的是,拥有停止计时器并在计算属性内弹出导航的代码是错误的。我更喜欢类似

Text("\(interval)").onReceive(timerManager.timer, perform: { _ in
  if self.interval <= 0 {
    self.mode.wrappedValue.dismiss()
    self.timerManager.stop()
  }
})

CountDownIntervalView内部,但这会生成编译器错误-Unable to infer complex closure return type; add explicit type to disambiguate-而且,老实说,我不确定 方法是否有意义(附加代码会有条件地将导航弹出到一个UI)。解决此问题的“最佳做法”是什么?

感谢您的任何想法。

1 个答案:

答案 0 :(得分:1)

这是一个解决方案。经过Xcode 11.4 / iOS 13.4的测试

Validation error. error C00CE169: App manifest validation error: The app manifest must be valid as per schema: Line 36, Column 16, Reason: '.*' violates pattern constraint of '[^<>":%\|\?\*\x01-\x1f]+'. The element '{http://schemas.microsoft.com/appx/manifest/uap/windows10}FileType' with value '.*' failed to parse.