My book on iOS interface design, Design Teardowns: Step-by-step iOS interface design walkthroughs is now available!

Delaying code execution

For a while now, this has been quite a tiresome exercise in Swift. Gone are the - (id)performSelector:(SEL)aSelector family of methods on NSObject and the corresponding cancelPreviousPerformRequestsWithTarget:selector:object: on the Class (meta?)object.

A quick search on StackOverflow shows the ideal way to perform delayed code execution is to use dispatch_after() from GCD. While it works, it's rather tedious to setup and has no built-in support for cancellation.

One quick way to solve this issue is through one level of indirection. Instead of executing the said closure directly, we somehow store it and later right before executing it, check again to see if we should.

The way I've chosen to do that is to simply store the closures in a dictionary. This way we can simply cancel the execution using the dictionary key:

typealias Closure = ()->()  
private var closures = [String: Closure]()

func delayed(delay: Double, name: String, closure: Closure) {  
    closures[name] = closure
    dispatch_after(
        dispatch_time(
            DISPATCH_TIME_NOW,
            Int64(delay * Double(NSEC_PER_SEC))
        ),
        dispatch_get_main_queue()) {
            if let closure = closures[name] {
                closure()
                closures[name] = nil                
            }
    }
}

The corresponding function to cancel execution is also extremely intuitive:

func cancelDelayed(name: String) {  
    closures[name] = nil
}