'How to cancel the delayed thread?
I am executing set of tasks, and in order to span them over time I've used Thread.sleep(forTimeInterval: ... )
It adds pauses between executions.
Then, on the main screen I have controllers, that can intervene into thread execution, so when controller applied I want to cancel the sleep. And start from the place of user's choice.
So, I've tried
Thread.exit()
- and it terminates the program with error.
How to exit (or, refresh) the current thread and start from the place I want? What are the ways to control the suspension of thread by button (i.e. controller)?
What actually happens is that if I cancel, it continues to run just from the same place...
let queue = DispatchQueue(label: "Actions Queue")
let delay: Double = 5
var actions = ["action 1", "action 2", "action 3", "action 4", "action 5"]
// every time task finishes, it calls for the following task (with delay)
queue.sync {
// sets an interval, that continues an action
Thread.sleep(forTimeInterval: TimeInterval(delay))
// continue an action
}
// heres how I've tried in main view, but it doesn't work
queue.sync {
Thread.current.cancel()
}
EDITS:
For example, what does the cancel()
do here? and why exit()
can't be applied to Thread.current
, but only to Thread.
"You can use these semantics to cancel the execution of a thread or determine if the thread is still executing or has finished its task". Okey, if I cancel()
. What, then will start it again?
queue.sync {
Thread.sleep(forTimeInterval: TimeInterval(10.0))
// do something
}
Button("...") {
queue.sync {
Thread.current.cancel()
}
}
Solution 1:[1]
As a general rule, I would advise against sleeping on a thread. First, we do not have preemptive cancelation. Second, it’s an inefficient use of resources, tying up that thread unnecessarily.
If you want to do something after a certain period of time, you have a few options:
Schedule a
Timer
and theninvalidate
it if you want to stop it.If using Swift concurrency (e.g.,
Task
,async
-await
, etc.), you canTask.sleep
, which, unlikeThread.sleep
, detects and handles cancelation.Thread.sleep
should be avoided, but with Swift concurrency, you can store theTask
in a property,cancel
it when appropriate, andTask.sleep
within theTask
will handle cancellation elegantly.You can create a
DispatchWorkItem
, dispatch it withasyncAfter
, and thencancel
if you don’t want that to happen.
If you have some cancelable tasks that you want to perform every x seconds, a single repeating Timer
is probably easiest, as you can invalidate
it and it stops the whole repeating series in one step. (It also avoids timer coalescing problems.)
You said:
what I am trying to achieve is - having a presentation that runs with predetermined time between slides, but if user wants to go back (or forward); it should cut straight away to previous slide and continue in the same manner of predetermined pauses.
I would suggest a repeating Timer
to advance to the next slide. If the user manually changes to another slide, invalidate
the old timer and create a new repeating Timer
.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 |