Create a gist now

Instantly share code, notes, and snippets.

What would you like to do?
Scheduled NSTimer with a Swift closure
extension NSTimer {
/**
Creates and schedules a one-time `NSTimer` instance.
- Parameters:
- delay: The delay before execution.
- handler: A closure to execute after `delay`.
- Returns: The newly-created `NSTimer` instance.
*/
class func schedule(delay delay: NSTimeInterval, handler: NSTimer! -> Void) -> NSTimer {
let fireDate = delay + CFAbsoluteTimeGetCurrent()
let timer = CFRunLoopTimerCreateWithHandler(kCFAllocatorDefault, fireDate, 0, 0, 0, handler)
CFRunLoopAddTimer(CFRunLoopGetCurrent(), timer, kCFRunLoopCommonModes)
return timer
}
/**
Creates and schedules a repeating `NSTimer` instance.
- Parameters:
- repeatInterval: The interval (in seconds) between each execution of
`handler`. Note that individual calls may be delayed; subsequent calls
to `handler` will be based on the time the timer was created.
- handler: A closure to execute at each `repeatInterval`.
- Returns: The newly-created `NSTimer` instance.
*/
class func schedule(repeatInterval interval: NSTimeInterval, handler: NSTimer! -> Void) -> NSTimer {
let fireDate = interval + CFAbsoluteTimeGetCurrent()
let timer = CFRunLoopTimerCreateWithHandler(kCFAllocatorDefault, fireDate, interval, 0, 0, handler)
CFRunLoopAddTimer(CFRunLoopGetCurrent(), timer, kCFRunLoopCommonModes)
return timer
}
}
// Usage:
var count = 0
NSTimer.schedule(repeatInterval: 1) { timer in
print(++count)
if count >= 10 {
timer.invalidate()
}
}
NSTimer.schedule(delay: 5) { timer in
print("5 seconds")
}

Consider using CFRunLoopTimerCreateWithHandler, which toll-free bridges to NSTimer.

Owner

natecook1000 commented Dec 2, 2014

Great suggestion, thanks! Makes the wrapper around the closure completely unnecessary.

Just a minor styling addition, I think scheduledTimerWithTimeInterval is too long for a method name and could be easily replaced here by schedule(interval: repeats).

So I'd prefer using it like NSTimer.schedule(interval: 1, repeats: true) which is more concise, yet as clear. (more thoughts on Swift method naming here)

Owner

natecook1000 commented Feb 4, 2015

@rinatkhanov, I like that idea too. I've split the original method into NSTimer.schedule(delay:handler:) and NSTimer.schedule(repeatInterval:handler:).

how can I use this extension to reset and restart the timer every 20 seconds? The method will be inserted in a UIButton action. Thanks!

julien-c commented Nov 1, 2016

This is what I'm running for Swift 3.0:

extension Timer {
    /**
    Creates and schedules a one-time `NSTimer` instance.

    :param: delay The delay before execution.
    :param: handler A closure to execute after `delay`.

    :returns: The newly-created `NSTimer` instance.
    */
    class func schedule(delay: TimeInterval, handler: @escaping (Timer?) -> Void) -> Timer {
        let fireDate = delay + CFAbsoluteTimeGetCurrent()
        let timer = CFRunLoopTimerCreateWithHandler(kCFAllocatorDefault, fireDate, 0, 0, 0, handler)!
        CFRunLoopAddTimer(CFRunLoopGetCurrent(), timer, CFRunLoopMode.commonModes)
        return timer
    }

    /**
    Creates and schedules a repeating `NSTimer` instance.

    :param: repeatInterval The interval between each execution of `handler`. Note that individual calls may be delayed; subsequent calls to `handler` will be based on the time the `NSTimer` was created.
    :param: handler A closure to execute after `delay`.

    :returns: The newly-created `NSTimer` instance.
    */
    class func schedule(repeatInterval interval: TimeInterval, handler: @escaping (Timer?) -> Void) -> Timer {
        let fireDate = interval + CFAbsoluteTimeGetCurrent()
        let timer = CFRunLoopTimerCreateWithHandler(kCFAllocatorDefault, fireDate, interval, 0, 0, handler)!
        CFRunLoopAddTimer(CFRunLoopGetCurrent(), timer, CFRunLoopMode.commonModes)
        return timer
    }
}

Also from iOS 10, there is a native method on Timer that does this: Timer.scheduledTimer(withTimeInterval: TimeInterval, repeats: Bool, block: (Timer) -> Void)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment