SoFunction
Updated on 2025-04-09

Introduction to the use of Dispatch Source Timer and precautions

Preface

Dispatch Source Timer is a timer used in conjunction with Dispatch Queue. When you need to perform tasks regularly in the background queue, using Dispatch Source Timer is more natural and more efficient than using NSTimer (no need to switch before the main queue and background queue). Below, we will introduce you in detail about the use of Dispatch Source Timer and some precautions. Without further ado, let’s take a look at the detailed introduction together.

Create Timer

Dispatch Source Timer First of all, it is actually a kind of Dispatch Source. The content about Dispatch Source will not be repeated here. The following is the code for creating a Dispatch Timer given in Apple's official documentation:

dispatch_source_t CreateDispatchTimer(uint64_t interval,
  uint64_t leeway,
  dispatch_queue_t queue,
  dispatch_block_t block)
{
 dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER,
       0, 0, queue);
 if (timer)
 {
 dispatch_source_set_timer(timer, dispatch_walltime(NULL, 0), interval, leeway);
 dispatch_source_set_event_handler(timer, block);
 dispatch_resume(timer);
 }
 return timer;
}

There are several places to pay attention to:

  1. Dispatch Source Timer is an interval timer, which means that the interval timer will fire every once in a while. To achieve the same effect in NSTimer, you need to manually set repeats to YES.
  2. The second parameter in dispatch_source_set_timer, when we use dispatch_time or DISPATCH_TIME_NOW, the system will use the default clock to time. However, when the system is sleeping, the default clock does not go, which will cause the timer to stop. Use dispatch_walltime to allow the timer to time at real time intervals.
  3. The fourth parameter of dispatch_source_set_timer, leeway, refers to an expected tolerance time, setting it to 1 second, meaning that the system may actually trigger the timer in the first or later 1 second of the timer time. It is recommended to set a reasonable leeway value when calling. It should be noted that even if the leeway value is specified as 0, the system cannot guarantee a completely accurate trigger time, but it will only meet this requirement as much as possible.
  4. The code in the event handler block will be executed in the specified queue. When queue is a background thread, dispatch timer is easier to operate than NSTimer. Because NSTimer requires Runloop support, if you want to use it in the background dispatch queue, you need to manually add Runloop. Using dispatch timer is much easier.
  5. After the dispatch_source_set_event_handler function is executed, the block will be executed immediately, and will be executed again at a certain time interval. The first execution of NSTimer is after the timer is triggered. This is also a significant difference from NSTimer.

Stop Timer

There are two ways to stop Dispatch Timer, one is to use dispatch_suspend, and the other is to use dispatch_source_cancel.

dispatch_suspend strictly just temporarily suspend Timer. It and dispatch_resume are a balanced call, which reduces and increases the suspend count of the dispatch object, respectively. When this count is greater than 0, Timer will execute. During the suspending period, the generated events will accumulate and will be fused into one event to be sent when resumed.

What should be noted is:dispatch source does not provide an API for detecting the suspend count of the source itself, which means that external cannot know whether a source is currently suspended. This must be taken into account when designing code logic.

dispatch_source_cancel is the real cancellation Timer. After being cancelled, if you want to execute Timer again, you can only recreate a new Timer. This process is similar to executing invalidate on an NSTimer.

About canceling Timer,Another very important thing to note:Timer after dispatch_suspend cannot be released! The following code will cause a crash:

- (void)stopTimer
{
 dispatch_suspend(_timer);
 _timer = nil; // EXC_BAD_INSTRUCTION Crashed}

Therefore, when using dispatch_suspend, the instance of Timer itself needs to be maintained all the time. Using dispatch_source_cancel does not have this restriction:

- (void)stopTimer
{
 dispatch_source_cancel(_timer);
 _timer = nil; // OK
}

Summarize

The above is the entire content of this article. I hope that the content of this article has a certain reference value for everyone's study or work. If you have any questions, you can leave a message to communicate. Thank you for your support.