我有一个由主 ContentView 和 TimerView 组成的导航视图。当我调用self.timer.upstream.connect().cancel()
时,TimerView的计时器可以正确递增并正确停止。
但是,当我返回ContentView然后再次导航到TimerView时,我希望计时器重新开始计数,但是这不会发生。 secondsElapsed
确实重置为0,但计时器没有运行。
import SwiftUI
struct ContentView: View {
var body: some View {
NavigationView {
NavigationLink(destination: TimerView()) {
Text("Go to Timer View")
}
}
}
}
struct TimerView: View {
@State var secondsElapsed = 0
var timer = Timer.publish (every: 1, on: .main, in: .common).autoconnect()
var body: some View {
VStack {
Text("\(self.secondsElapsed) seconds elapsed")
Button("Stop timer",
action: {
self.timer.upstream.connect().cancel()
})
}.onReceive(timer) { _ in
self.secondsElapsed += 1
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
答案 0 :(得分:12)
据我所知(以及历史上的经验),取消或无效后无法重新启动Timer。
我要做的就是重新声明计时器。
以下是添加了一些个人喜好的示例:
struct TimerView: View {
@State var secondsElapsed = 0
@State var timer: Timer.TimerPublisher = Timer.publish (every: 1, on: .main, in: .common)
var body: some View {
VStack {
Text("\(self.secondsElapsed) seconds elapsed")
Button("Stop timer",
action: {
self.cancelTimer() // Just to be a little more DRY/maintenance-friendly, but personal preference.
})
}.onAppear(perform: {
self.instantiateTimer() // You could also consider an optional self.timer variable.
self.timer.connect() // This allows you to manually connect where you want with greater efficiency, if you don't always want to autostart.
}).onDisappear(perform: {
// I don't know your exact flow, but you said you want the timer to restart upon return navigation.
// So, I am just assuming you want to stop the timer when you navigate out.
// But, you can also easily remove this closure.
// Also, this may not run as you would intuit.
self.cancelTimer()
}).onReceive(timer) { _ in
self.secondsElapsed += 1
}
}
func instantiateTimer() {
self.timer = Timer.publish (every: 1, on: .main, in: .common)
return
}
func cancelTimer() {
self.timer.connect().cancel()
return
}
}
答案 1 :(得分:1)
在View
内没有附加到@State
变量或@ObservedObject
模型中的变量似乎没有定义明确的文档-但一般规则是所有没有@State/@ObservedObject
批注的东西都是丢弃的-尤其是TimerView
是struct
,并且不会在重新渲染时保留。
Timer.TimerPublisher
是一个类-因此从本质上讲,这可以归结为两个用例
@State
中(请注意self
捕获具有很强的保留性-再次缺少文档onReceive
如何存储其连接)var
)并通过init
调用将其引入TimerView
您拥有@State var secondsElapsed
使我认为它应该是短暂的
答案 2 :(得分:1)
如果你有一个倒数计时器,你可以像这样定义它:
let timer = Timer.publish(every: 1, on: .main, in: .common).autoconnect()
...并在文本字段上使用它,例如:
Text("Punkte: \(Punkte.formatnumber())")
.onReceive(timer) { input in
if time < 1 { gameOver() } else { self.time -= TimerToggle ? 1 : 0 }
}
所以你只需要在按钮的动作中设置切换:
Button(action: { TimerToggle.toggle() }, label: {
Text("Pause")
})
更简单,适用于 SwiftUI 5.2
答案 3 :(得分:-2)