SwiftUI - 可选计时器,重置和重新创建
SwiftUI - Optional Timer, reset and recreate
通常,我会使用一个可选变量来保存我的 Timer
引用,因为能够 invalidate 并将其设置为 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)")
}
这个 Combine
类型的 Timer
无效和重新创建的正确方法是什么?
我读过一个应该调用:
self.timer.upstream.connect().cancel()
但是,我还需要 invalidate 还是直接 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 \([=10=])"
}
}
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
}
}
通常,我会使用一个可选变量来保存我的 Timer
引用,因为能够 invalidate 并将其设置为 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)")
}
这个 Combine
类型的 Timer
无效和重新创建的正确方法是什么?
我读过一个应该调用:
self.timer.upstream.connect().cancel()
但是,我还需要 invalidate 还是直接 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 \([=10=])"
}
}
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
}
}