Skip to content

Instantly share code, notes, and snippets.

@radex
Last active May 30, 2018 10:33
Show Gist options
  • Star 18 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save radex/41a1e75bb1290fb5d559 to your computer and use it in GitHub Desktop.
Save radex/41a1e75bb1290fb5d559 to your computer and use it in GitHub Desktop.
Swift Extensions: NSTimer

NSTimer is a great example of an over-verbose, outdated Objective-C API. To run a simple line of code after a delay, you need to write a lot of boilerplate crap.

How about this:

NSTimer.schedule(5.seconds) {
  println("Hello world!")
}

So much better. How about a timer that repeats every second? Swift supports optional parameters, so we could do repeat: true, but how about:

NSTimer.schedule(every: 1.second) {
  println("Hello world!")
}

Sweet. But what if you want to schedule the timer yourself? (e.g. for event tracking run loop mode)? Just cut the .schedule part out:

let timer = NSTimer(every: 1.second) { println("Hello world!") }

Want to use a separate method after all? No problem:

func printFoo() {
  println("Hello world!")
}

NSTimer.schedule(1.second, block: printFoo)

(after all, functions and methods are just named closures)

PS. I wrote something very similar in Objective-C before.


Previously in Swift Extensions:

import Foundation
private class NSTimerActor {
var block: () -> ()
init(block: () -> ()) {
self.block = block
}
dynamic func fire() {
block()
}
}
extension NSTimer {
convenience init(_ intervalFromNow: NSTimeInterval, block: () -> ()) {
let actor = NSTimerActor(block: block)
self.init(timeInterval: intervalFromNow, target: actor, selector: "fire", userInfo: nil, repeats: false)
}
convenience init(every interval: NSTimeInterval, block: () -> ()) {
let actor = NSTimerActor(block: block)
self.init(timeInterval: interval, target: actor, selector: "fire", userInfo: nil, repeats: true)
}
class func schedule(intervalFromNow: NSTimeInterval, block: () -> ()) -> NSTimer {
let timer = NSTimer(intervalFromNow, block)
NSRunLoop.currentRunLoop().addTimer(timer, forMode: NSDefaultRunLoopMode)
return timer
}
class func schedule(every interval: NSTimeInterval, block: () -> ()) -> NSTimer {
let timer = NSTimer(every: interval, block)
NSRunLoop.currentRunLoop().addTimer(timer, forMode: NSDefaultRunLoopMode)
return timer
}
}
import Foundation
extension Int {
var second: NSTimeInterval { return NSTimeInterval(self) }
var seconds: NSTimeInterval { return NSTimeInterval(self) }
var minute: NSTimeInterval { return NSTimeInterval(self * 60) }
var minutes: NSTimeInterval { return NSTimeInterval(self * 60) }
var hour: NSTimeInterval { return NSTimeInterval(self * 3600) }
var hours: NSTimeInterval { return NSTimeInterval(self * 3600) }
}
extension Double {
var second: NSTimeInterval { return self }
var seconds: NSTimeInterval { return self }
var minute: NSTimeInterval { return self * 60 }
var minutes: NSTimeInterval { return self * 60 }
var hour: NSTimeInterval { return self * 3600 }
var hours: NSTimeInterval { return self * 3600 }
}
@schickling
Copy link

Great job!

@ofeksher8
Copy link

it's not work at swift 2 :/

@Multiforge
Copy link

Just use SwiftyTImer, it's the same thing, it works with Swift 2, and it's a cocoa pod so it's easy to install.

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