1. Overview
Speaking of timers, many developers will think of Timer at the first time, but as they deepen their use, they gradually find that Timer is not very useful, such as if TableView is not executed when sliding, Timer loops.
2. DispatchSourceTimer
DispatchSourceTimer, which is commonly called GCD Timer, is a timer that relies on GCD. This timer is also used in the underlying code of Runloop. It can be seen that GCD Timer does not rely on Runloop.
Let’s take a look at the definition of Apple:
A dispatch source that submits the event handler block based on a timer.
2.1 GCD Timer Creation
Use the following method to create a DispatchSourceTimer object.
class func makeTimerSource(flags: = [], queue: DispatchQueue? = nil) -> DispatchSourceTimer // By default, scheduled in the main queuelet timer = () // Specify the scheduled usage in the main queuelet timer = (flags: [], queue: ) // Specify the use of scheduling in the global queuelet timer = (flags: [], queue: ()) // Specify the scheduled usage in a custom queuelet customQueue = DispatchQueue(label: "customQueue") let timer = (flags: [], queue: customQueue)
2.2 GCD Timer Configuration
To configure Timer parameters, you need to use the DispatchSourceTimer protocol method. Timers that can be triggered one or more times can be scheduled. Every time Timer fires, it calls the deployed task.
// From now on, execute once a second. timer?.schedule(deadline: (), repeating: .seconds(1), leeway: .nanoseconds(1)) // Execute the task after 5 seconds, without repeating it. timer?.schedule(deadline: () + 5, repeating: .never, leeway: .nanoseconds(1))
2.3 GCD Timer deployment tasks
After Timer has configured parameters, use the DispatchSourceProtocol protocol method to deploy the task to be executed.
The difference between setEventHandler and setRegistrationHandler:
- setEventHandler: Sets the task to be executed for the Timer, including one-time tasks and timed repetition tasks. The callback method is executed in the child thread.
- setRegistrationHandler: The task set by this method will only be executed once, that is, it will be executed when the Timer is ready to run, similar to a notification callback that the Timer starts. The callback method is executed in the child thread.
For example, the following code:
var timer: DispatchSourceTimer? func initTimer() { // By default, scheduled in the main queue timer = () // From now on, execute once a second. timer?.schedule(deadline: (), repeating: .seconds(1), leeway: .nanoseconds(1)) // 5Execute tasks in seconds,No repetition。
// timer?.schedule(deadline: () + 5, repeating: .never, leeway: .nanoseconds(1))
timer?.setEventHandler { { print("Execute tasks") } } timer?.setRegistrationHandler(handler: { { print("Timer is working") } }) timer?.activate() }
The execution results are as follows:
2020-11-28 02:20:00 +0000 Timer has started working
2020-11-28 02:20:00 +0000 Execute tasks
2020-11-28 02:20:01 +0000 Execute tasks
2020-11-28 02:20:02 +0000 Execute tasks
2.4 GCD Timer control method
Let’s take a look at the control method and status of Timer:
- activate() : After creating a Timer, it is in an inactive state, so to execute the Timer, this method needs to be called.
- suspend() : When the Timer starts running, calling this method will suspend the Timer, that is, pause.
- resume() : When the Timer is suspended, calling the method will continue to run the Timer.
- cancel() : After calling this method, the Timer will be cancelled. If the canceled Timer wants to execute the task again, it needs to be recreated.
If the above methods are used improperly, it is easy to cause APP to crash. Let’s take a look at the specific precautions and suggestions:
- When the Timer is created, it is recommended to call the activated() method to start running. If you call resume() directly, you can start running.
- When suspend(), the event event currently being executed will not stop, but the next event event will be stopped.
- When Timer is in suspend state, if Timer or its controller is destroyed, the APP will crash.
- 2020-11-28 02:20:00 +0000 Timer has started working
2020-11-28 02:20:00 +0000 Execute tasks
2020-11-28 02:20:01 +0000 Execute tasks
2020-11-28 02:20:02 +0000 Execute tasks
suspend() and resume() need to appear in pairs, suspend once, and resume once. If the Timer starts running, call resume() directly when there is no suspend, it will cause the APP to crash. - When using cancel(), if Timer is in suspend state, the APP crashes.
- In addition, you need to pay attention to the circular reference problem of block.
2.5 Dual loop DispatchSourceTimer
For example: When we need a certain time (array length * 4), print the corresponding subscript every once in a while (each element is printed at 4 seconds), print infinitely
Using DispatchSourceTimer in the double loop in the example below, you will find that print only prints dom some = 0 This is not the effect we want
var exaltedTimer: DispatchSourceTimer? func demo { let arr = [1,2,3,4] = () ?.schedule(deadline: .now(), repeating: TimeInterval(*4)) ?.setEventHandler(handler: { for (index, item) in () { let timer2 = () (deadline: .now()+4.0*CGFloat(index), repeating: .infinity) { { print("do some = \(index)") } } () } }) ?.activate() }
This is because timer2 is released after use, so cancel and resume need to be used together, so we achieve the desired effect.
var exaltedTimer: DispatchSourceTimer? var exaltedTimerArray: [DispatchSourceTimer] = [] func demo { ?.cancel() for subTimer in { () } let arr = [1,2,3,4] = () ?.schedule(deadline: .now(), repeating: TimeInterval(*4)) ?.setEventHandler(handler: { for (index, item) in () { let timer2 = () (deadline: .now()+4.0*CGFloat(index), repeating: .infinity) { { print("do some = \(index)") } } (timer2) () } }) ?.resume()
Reference article
/guoyongming925/article/details/110224064
This is the article about the specific use of the iOS DispatchSourceTimer timer. For more information about iOS DispatchSourceTimer timer, please search for my previous articles or continue browsing the following related articles. I hope everyone will support me in the future!