A Swift Repeating Timer

A Swift function to create and start a timer dispatch source.

We frequently (excuse the pun) need to schedule a repeated action.

The way to do this was usually to use NSTimer’s scheduledTimerWithTimeInterval(_:,target:,selector:,userInfo:,repeats:), which needed a callback, and had the hidden pitfall of the target being strongly referenced by the runloop that this timer was scheduled on. There are extensions to NSTimer that allow the used of blocks instead (I even wrote one myself), but there is another way.

Grand Central Dispatch provides dispatch sources for efficient interaction with the underlying system. One such source type is DISPATCH_SOURCE_TYPE_TIMER. So here as a Swift function that creates and starts such a timer.

//
// RepeatingTimer.swift
//

import Foundation

enum TimerError: ErrorType {
    /// The timer could not be created.
    case CouldNotCreate
}

/**
Create and start a timer dispatch source.
This is best used for short running timers. Be sure to call `dispatch_source_cancel()` on the timer to invalidate it.
- Parameters:
- interval: The interval for the timer.
- leeway:   The amount of time that the system can defer the timer.
- start:    The start time of the timer. Defaults to DISPATCH_TIME_NOW
- queue:    The dispatch queue to which the action closure is submitted. Defaults to the main queue.
- action:   The closure to submit to the queue. Has the signature of () -> Void
- Returns: A dispatch source timer that has already been started.
- Throws: A `TimerError.CouldNotCreate` error if the timer could not be created.
*/
@warn_unused_result
func repeatingTimerWithInterval(
    interval: NSTimeInterval,
    leeway: NSTimeInterval,
    start: dispatch_time_t = DISPATCH_TIME_NOW,
    queue: dispatch_queue_t = dispatch_get_main_queue(),
    action: dispatch_block_t)
    throws -> dispatch_source_t {

        let timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue)
        guard timer != nil else { throw TimerError.CouldNotCreate }

        func nanoseconds(seconds: NSTimeInterval) -> UInt64 {
            enum Static { static let Multiplier = Double(NSEC_PER_SEC) }

            return UInt64(seconds * Static.Multiplier)
        }

        dispatch_source_set_event_handler(timer, action)
        dispatch_source_set_timer(timer, start, nanoseconds(interval), nanoseconds(leeway))

        dispatch_resume(timer)

        return timer
}

Since I’m passing in NSTimeIntervals this is probably best used for short lived timers, but it extracts a lot of the C boilerplate that is needed to create the dispatch source.