英文:
Timer won't stop - .upstream.connect().cancel()
问题
以下是翻译好的部分:
我试图运行一些带有定时器的代码,然后在满足某些条件时停止定时器。
以下是代码的相关部分:
let updateTimer = Timer.publish(every: 5, on: .main, in: .common).autoconnect()
以及 .onReceive
部分:
.onReceive(updateTimer) { _ in
if (story.status == "ready") {
am.pollingFinished = true
print("Update Timer Canceled (1)")
updateTimer.upstream.connect().cancel()
}
if (am.pollingFinished) {
print("Update Timer Canceled (2)")
updateTimer.upstream.connect().cancel()
}
}
然而,正如您从以下控制台日志打印所看到的,尽管满足条件,时间仍在运行:
有什么建议吗?
英文:
I am trying to run a some code with a timer, and then stop the timer when some conditions are met.
Here are the relevant parts of the code:
let updateTimer = Timer.publish(every: 5, on: .main, in: .common).autoconnect()
And the .onReceive
.onReceive(updateTimer) { _ in
if (story.status == "ready"){
am.pollingFinished = true
print("Update Timr Canceled (1)")
updateTimer.upstream.connect().cancel()
}
if (am.pollingFinished) {
print("Update Timr Canceled (2)")
updateTimer.upstream.connect().cancel()
}
Yet, as you can see from the following console prints, the time keeps running, even though the conditions are met
Any ideas why?
答案1
得分: 1
不自动连接,你需要手动连接并存储生成的 Cancellable。这个对象之后用来取消操作。你还需要显式订阅 Timer 发布者。你不需要保留对 Timer 发布者的引用,只需要保留 Cancellable。如果你将 Timer Cancellable 保留在一个单独的类对象中,将在 SwiftUI 下更容易处理。
老实说,我不明白为什么要使用 Timer 发布者;个人而言,我会直接使用实际的 Timer。然而,如果你坚持使用发布者,下面是一个示例,说明了我刚刚描述的架构:
class TimerManager: ObservableObject {
var cancellables = Set<AnyCancellable>()
func makeTimerPublisher() -> AnyPublisher<Date, Never> {
let timerPublisher = Timer.publish(every: 1, on: .main, in: .default)
timerPublisher.connect().store(in: &cancellables)
return timerPublisher.eraseToAnyPublisher()
}
func stop() {
cancellables.removeAll()
}
}
struct ContentView: View {
@StateObject var timerManager = TimerManager()
@State var labelText: String = ""
var body: some View {
VStack {
Text(labelText)
Button("Stop") { timerManager.stop() }
}
.onReceive(timerManager.makeTimerPublisher()) { labelText = String(describing: $0) }
}
}
请注意,代码部分未被翻译。
英文:
Instead of auto connecting, you need to connect manually and store the resulting Cancellable. That is the object you later cancel. You will also need to subscribe to the Timer publisher explicitly. You do not need to keep a reference to the Timer publisher — just the Cancellable. You will find this a lot more tractable under SwiftUI if you keep the Timer Cancellable in a separate class object.
To be quite honest I don't see why you use a Timer publisher at all; personally, I would just use an actual Timer. However, if you insist on using a publisher, here's an example that illustrates the architecture I've just described:
class TimerManager: ObservableObject {
var cancellables = Set<AnyCancellable>()
func makeTimerPublisher() -> AnyPublisher<Date, Never> {
let timerPublisher = Timer.publish(every: 1, on: .main, in: .default)
timerPublisher.connect().store(in: &cancellables)
return timerPublisher.eraseToAnyPublisher()
}
func stop() {
cancellables.removeAll()
}
}
struct ContentView: View {
@StateObject var timerManager = TimerManager()
@State var labelText: String = ""
var body: some View {
VStack {
Text(labelText)
Button("Stop") { timerManager.stop() }
}
.onReceive(timerManager.makeTimerPublisher()) { labelText = String(describing: $0) }
}
}
答案2
得分: 1
示例中的并发。一切都相当简单:
struct ContentView: View {
var body: some View {
Text("Hello, World!").task {
do {
for _ in 0..<5 {
try await Task.sleep(for: .seconds(5))
print("timer fired")
}
} catch {
print("timer cancelled")
}
print("timer done")
}
}
}
英文:
Example with Concurrency. All is quite simple:
struct ContentView: View {
var body: some View {
Text("Hello, World!").task {
do {
for _ in 0..<5 {
try await Task.sleep(for: .seconds(5))
print("timer fired")
}
} catch {
print("timer cancelled")
}
print("timer done")
}
}
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论