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()
}
}
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 then invalidate
it if you want to stop it.
If using Swift concurrency (e.g., Task
, async
-await
, etc.), you can Task.sleep
, which, unlike Thread.sleep
, detects and handles cancelation. Thread.sleep
should be avoided, but with Swift concurrency, you can store the Task
in a property, cancel
it when appropriate, and Task.sleep
within the Task
will handle cancellation elegantly.
You can create a DispatchWorkItem
, dispatch it with asyncAfter
, and then cancel
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
.