通常,我会使用一个可选变量来保存我的timer
引用,因为能够在重新创建之前使其无效并将其设置为nil
是件好事。
我正在尝试使用Swiftui
,并希望确保操作正确。。。
我宣布:
@State var timer:Publishers.Autoconnect<Timer.TimerPublisher>? = nil
后来我:
self.timer = Timer.publish(every: 1, on: .main, in: .common).autoconnect()
要驱动UI文本控件,我使用:
.onReceive(timer) { time in
print("The time is now \(time)")
}
使用此组合
键入的计时器
使其无效和重新创建的正确方法是什么?
我读过一个应该叫:
self.timer.upstream.connect().cancel()
但是,我是否也需要使nil
out无效?
没有必要丢弃TimerPublisher
本身。 Timer.Publish
创建一个Timer.TimerPublisher
实例,该实例与所有其他发布服务器一样,仅在您创建对它的订阅时才开始发出值,并且一旦订阅关闭,它就会停止发出值。
因此,无需重新创建TimerPublisher
,只需在需要时重新创建对它的订阅。
因此,在声明上分配timer.publish
,但不要autoconnect()
它。 无论何时要启动计时器,请调用计时器上的connect
并将cancellable
保存在实例属性中。 然后无论何时要停止计时器,调用cancellable
上的cancel
并将其设置为nil
。
您可以在下面找到一个完全工作的视图,其中有一个预览,该预览在5秒后启动计时器,每秒更新一次视图,并在30秒后停止流。
通过将发布服务器和订阅存储在视图模型上并将其注入到视图中,可以进一步改进这一点。
struct TimerView: View {
@State private var text: String = "Not started"
private var timerSubscription: Cancellable?
private let timer = Timer.publish(every: 1, on: .main, in: .common)
var body: some View {
Text(text)
.onReceive(timer) {
self.text = "The time is now \($0)"
}
}
mutating func startTimer() {
timerSubscription = timer.connect()
}
mutating func stopTimer() {
timerSubscription?.cancel()
timerSubscription = nil
}
}
struct TimerView_Previews: PreviewProvider {
static var previews: some View {
var timerView = TimerView()
DispatchQueue.main.asyncAfter(deadline: .now() + 5) {
timerView.startTimer()
}
DispatchQueue.main.asyncAfter(deadline: .now() + 30) {
timerView.stopTimer()
}
return timerView
}
}
使用视图模型,您甚至不需要向视图公开TimerPublisher
(或任何Publisher
),而只需更新@published
属性并将其显示在视图的body
中。 这使您可以将timer
声明为autoconnect
,这意味着您不需要手动调用它上的cancel
,您可以简单地将订阅引用nil
输出以停止计时器。
class TimerViewModel: ObservableObject {
private let timer = Timer.publish(every: 1, on: .main, in: .common).autoconnect()
private var timerSubscription: Cancellable?
@Published var time: Date = Date()
func startTimer() {
timerSubscription = timer.assign(to: \.time, on: self)
}
func stopTimer() {
timerSubscription = nil
}
}
struct TimerView: View {
@ObservedObject var viewModel: TimerViewModel
var body: some View {
Text(viewModel.time.description)
}
}
struct TimerView_Previews: PreviewProvider {
static var previews: some View {
let viewModel = TimerViewModel()
let timerView = TimerView(viewModel: viewModel)
DispatchQueue.main.asyncAfter(deadline: .now() + 5) {
viewModel.startTimer()
}
DispatchQueue.main.asyncAfter(deadline: .now() + 30) {
viewModel.stopTimer()
}
return timerView
}
}