Instantly share code, notes, and snippets.

Embed
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")
}
@zwaldowski

This comment has been minimized.

Show comment
Hide comment
@zwaldowski

zwaldowski Nov 24, 2014

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

zwaldowski commented Nov 24, 2014

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

@natecook1000

This comment has been minimized.

Show comment
Hide comment
@natecook1000

natecook1000 Dec 2, 2014

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

Owner

natecook1000 commented Dec 2, 2014

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

@rinatkhanov

This comment has been minimized.

Show comment
Hide comment
@rinatkhanov

rinatkhanov Jan 13, 2015

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)

rinatkhanov commented Jan 13, 2015

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)

@natecook1000

This comment has been minimized.

Show comment
Hide comment
@natecook1000

natecook1000 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:).

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:).

@simogerard

This comment has been minimized.

Show comment
Hide comment
@simogerard

simogerard Jul 14, 2015

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!

simogerard commented Jul 14, 2015

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

This comment has been minimized.

Show comment
Hide comment
@julien-c

julien-c 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)

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