# How to Implement an Efficient Repeating Timer in Swift Using DispatchSourceTimer

> Implement an efficient repeating timer in Swift using DispatchSourceTimer for nanosecond-precision execution. Avoid RunLoop jitter and UI thread contention with this low-overhead solution.

- Repository: [Apple/swift](https://github.com/apple/swift)
- Tags: how-to-guide
- Published: 2026-02-19

---

**Use `DispatchSource.makeTimerSource()` to create a `DispatchSourceTimer` on a dedicated `DispatchQueue` for nanosecond‑precision, low‑overhead periodic execution that avoids RunLoop jitter and UI thread contention.**

Efficient repeating timers in Swift require careful selection of underlying timing mechanisms to balance precision, resource usage, and thread safety. While Foundation's `Timer` class is familiar to many developers, the apple/swift repository demonstrates that Grand Central Dispatch (GCD) provides a more performant alternative for background tasks. According to benchmark utilities and standard library tests in the Swift codebase, `DispatchSourceTimer` delivers superior performance through kernel‑driven scheduling and direct access to high‑resolution system clocks.

## Why DispatchSourceTimer is the Most Efficient Approach

When comparing timing mechanisms, `DispatchSourceTimer` outperforms `Foundation.Timer` and `CADisplayLink` across critical dimensions including precision, thread affinity, and power efficiency.

### Nanosecond Precision via Mach Timebase

`DispatchSourceTimer` achieves nanosecond‑level accuracy by leveraging `mach_absolute_time` on Apple platforms and `clock_gettime` on Linux. This contrasts with Foundation `Timer`, which operates at millisecond precision and suffers from RunLoop jitter.

In [`benchmark/utils/DriverUtils.swift`](https://github.com/apple/swift/blob/main/benchmark/utils/DriverUtils.swift) (lines 320‑558), the Swift repository implements a custom `Timer` utility that reveals this low‑level architecture:

```swift
final class Timer {
#if os(Linux)
  typealias TimeT = timespec
  func getTime() -> TimeT { /* uses clock_gettime */ }
  func diffTimeInNanoSeconds(...) -> UInt64 { /* normalizes nanoseconds */ }
#else
  typealias TimeT = UInt64
  var info = mach_timebase_info_data_t()
  init() { mach_timebase_info(&info) }
  func getTime() -> TimeT { return mach_absolute_time() }
  func diffTimeInNanoSeconds(...) -> UInt64 { /* scales via timebase info */ }
#endif
}

```

This implementation mirrors the mechanism that `DispatchSourceTimer` utilizes internally, bypassing the higher‑level RunLoop abstraction for direct kernel access.

### Thread Safety and Queue Targeting

Unlike `Foundation.Timer`, which requires attachment to a specific `RunLoop` and often forces execution on the main thread, `DispatchSourceTimer` can target any `DispatchQueue`. This eliminates UI blocking by scheduling work on background queues.

The test suite in [`test/stdlib/DispatchTypes.swift`](https://github.com/apple/swift/blob/main/test/stdlib/DispatchTypes.swift) (line 42) demonstrates the canonical instantiation pattern:

```swift
let source = DispatchSource.makeTimerSource()

```

### Low Resource Overhead

`DispatchSourceTimer` operates as a fully kernel‑driven mechanism that wakes only when the interval expires. This design minimizes CPU wake‑ups and power consumption compared to `Foundation.Timer`, which requires RunLoop bookkeeping and can unnecessarily wake the UI thread.

## Implementing Repeating Timers in Production Code

The following patterns demonstrate how to implement efficient repeating timers using GCD, as validated by the Swift repository's sanitizer tests and benchmark harness.

### Basic Background Timer

Create a timer on a dedicated utility queue to prevent main thread contention:

```swift
import Dispatch

let timerQueue = DispatchQueue(label: "com.example.timer", qos: .utility)
let timer = DispatchSource.makeTimerSource(queue: timerQueue)

// Schedule first fire after 500ms, then repeat every 2 seconds
timer.schedule(deadline: .now() + .milliseconds(500),
               repeating: .seconds(2),
               leeway: .milliseconds(100))

timer.setEventHandler {
    print("Executing periodic task")
}

// Activation required after configuration
timer.resume()

```

The `leeway` parameter allows the system to optimize power by shifting the deadline slightly without affecting logical correctness.

### Dynamically Reconfigurable Timer

For scenarios requiring runtime interval changes, encapsulate the timer in a class that exposes fine‑grained control:

```swift
class ReconfigurableTimer {
    private let source: DispatchSourceTimer
    private let queue: DispatchQueue

    init(queue: DispatchQueue = .global()) {
        self.queue = queue
        self.source = DispatchSource.makeTimerSource(queue: queue)
        self.source.setEventHandler(handler: work)
        self.source.resume()
    }

    private func work() {
        // Periodic task execution
    }

    func schedule(after interval: DispatchTimeInterval,
                  repeatEvery repeatInterval: DispatchTimeInterval) {
        source.schedule(deadline: .now() + interval,
                       repeating: repeatInterval)
    }

    func cancel() {
        source.cancel()
    }
}

```

This pattern appears in concurrent testing scenarios such as [`test/Sanitizers/tsan/norace-block-release.swift`](https://github.com/apple/swift/blob/main/test/Sanitizers/tsan/norace-block-release.swift) (lines 25‑27), where timer lifecycle management must be explicit and thread‑safe.

### High‑Frequency Sub‑Millisecond Timer

For audio processing or physics simulation requiring sub‑millisecond resolution:

```swift
let hiResTimer = DispatchSource.makeTimerSource()
hiResTimer.schedule(deadline: .now(),
                    repeating: .nanoseconds(500_000), // 0.5ms
                    leeway: .nanoseconds(100_000))
hiResTimer.setEventHandler { 
    // Real‑time critical work
}
hiResTimer.resume()

```

## Source Code References in the Swift Repository

The apple/swift repository provides authoritative implementation examples that demonstrate `DispatchSourceTimer` usage in production environments:

- **[`benchmark/utils/DriverUtils.swift`](https://github.com/apple/swift/blob/main/benchmark/utils/DriverUtils.swift)** (lines 320‑558): Contains a cross‑platform `Timer` class using `mach_absolute_time` and `clock_gettime` that illustrates the underlying timing mechanisms available to `DispatchSourceTimer`.
- **[`test/stdlib/DispatchTypes.swift`](https://github.com/apple/swift/blob/main/test/stdlib/DispatchTypes.swift)** (line 42): Demonstrates the standard `DispatchSource.makeTimerSource()` factory method used throughout the Swift test suite.
- **[`test/Sanitizers/tsan/norace-block-release.swift`](https://github.com/apple/swift/blob/main/test/Sanitizers/tsan/norace-block-release.swift)** (lines 25‑27): Shows `DispatchSourceTimer` usage in ThreadSanitizer tests, validating thread‑safe timer cancellation patterns.
- **[`stdlib/public/Platform/POSIXError.swift`](https://github.com/apple/swift/blob/main/stdlib/public/Platform/POSIXError.swift)** (line 158): Defines timer‑related error handling that integrates with system‑level timer failures.

## Summary

- **`DispatchSourceTimer`** provides the most efficient repeating timer implementation in Swift, utilizing kernel‑driven scheduling and nanosecond‑precision clocks.
- Target **dedicated `DispatchQueue`** instances rather than the main RunLoop to eliminate UI thread contention.
- Use **`schedule(deadline:repeating:leeway:)`** to configure intervals, specifying leeway for power optimization.
- Call **`resume()`** only after configuring handlers and schedules to prevent premature firing.
- Invoke **`cancel()`** for clean shutdown, optionally setting a cancellation handler for resource cleanup.

## Frequently Asked Questions

### What is the difference between DispatchSourceTimer and Foundation Timer?

`DispatchSourceTimer` operates at the kernel level using `mach_absolute_time` or `clock_gettime`, providing nanosecond precision and queue‑based execution without RunLoop overhead. `Foundation.Timer` runs on a `RunLoop`, offers only millisecond precision, and typically requires the main thread, causing potential UI blocking and higher power consumption due to frequent wake‑ups.

### How do I cancel a DispatchSourceTimer correctly?

Call `timer.cancel()` to stop future invocations. If you need to perform cleanup after cancellation, set a cancellation handler using `setCancelHandler` before calling `cancel`. The cancellation handler executes on the timer's target queue once the timer is fully stopped, as demonstrated in the ThreadSanitizer tests within the Swift repository.

### Can I use DispatchSourceTimer on the main thread for UI updates?

Yes, by initializing the timer with `DispatchQueue.main` as the target queue: `DispatchSource.makeTimerSource(queue: DispatchQueue.main)`. However, for UI updates, `CADisplayLink` is often more appropriate as it synchronizes with the display refresh rate. Reserve `DispatchSourceTimer` on the main queue only when you need precise timing control for UI‑related tasks without display synchronization.

### What is the maximum precision available with DispatchSourceTimer?

On Apple platforms, `DispatchSourceTimer` utilizes the Mach absolute time facility (`mach_absolute_time`), providing nanosecond‑level resolution. On Linux, it uses `clock_gettime` with `CLOCK_MONOTONIC`. You can specify intervals in nanoseconds using `.nanoseconds()`, though actual precision depends on hardware capabilities and system load. The benchmark utilities in [`benchmark/utils/DriverUtils.swift`](https://github.com/apple/swift/blob/main/benchmark/utils/DriverUtils.swift) demonstrate how to calculate nanosecond differences using the Mach timebase info conversion factor.