I am trying to cancel a delayed execution of a function running on the main queue, in a tap gesture, I found a way to create a cancellable DispatchWorkItem
, but the issue I have is that it’s getting created every time while tapping, and then when I cancel the execution, I actually cancel the new delayed execution and not the first one.
Here is a simpler example with a Timer
instead of a DispatchQueue.main.asyncAfter
:
.onTapGesture {
isDeleting.toggle()
let timer = Timer.scheduledTimer(withTimeInterval: 2.0, repeats: false) { timer in
completeTask()
}
if !isDeleting {
timer.invalidate()
}
}
completeTask:
private func completeTask() {
tasksViewModel.deleteTask(task: task) // task is declared above this func at the top level of the struct and so is tasksViewModel, etc.
guard let userID = userViewModel.id?.uuidString else { return }
Task {
//do some async stuff
}
}
As you can see if I click it once the timer fires, but if I click it again, another timer fires and straight away invalidates, but the first timer is still running.
So I have to find a way to create only one instance of that timer.
I tried putting it in the top level of the struct and not inside the var body
but the issue now is that I can’t use completeTask()
because it uses variables that are declared at the same scope.
Also, can’t use a lazy initialization because it is an immutable struct.
My goal is to eventually let the user cancel a timed task and reactivate it at will on tapping a button/view. Also, the timed task should use variables that are declared at the top level of the struct.
2
Answers
that is my solution mb can help you
var timer: Timer?
for stop use
scrollItem?.cancel()
for start call func
First of all you need to create a strong reference of timer on local context like so:
and then, set the timer value on
onTapGesture
closure:and after that you can invalidate this Timer whenever you need by accessing the local variable
timer
like this: