GCD would have to be involved anyway, since the question mentioned doing calculations in the background and then updating the UI, but of course then we could restrict it to just calling dispatch_async().
Here is a solution using a timer source, but is a bit messier than the dispatch_after solution. Also, the timer source has to be stored somewhere, since the timer stops if it is deallocated. The advantage is that the timer can be canceled.
func runevery(seconds: Double, closure: () -> ()) -> dispatch_source_t {
let timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_global_queue(QOS_CLASS_BACKGROUND, 0))
dispatch_source_set_timer(timer, dispatch_walltime(nil, 0), UInt64(seconds * Double(NSEC_PER_SEC)), 10 * NSEC_PER_MSEC)
dispatch_source_set_event_handler(timer, closure)
dispatch_resume(timer)
return timer
}
An NSTimer based solution:
class TimerReceiver {
@objc func periodic() {
dispatch_async(dispatch_get_global_queue(QOS_CLASS_BACKGROUND, 0)) {
print("\n Doing calculations\n")
dispatch_async(dispatch_get_main_queue()) {
print("\n !!! UPDATING UI !!!\n")
}
}
}
}
let receiver = TimerReceiver()
let timer = NSTimer.scheduledTimerWithTimeInterval(5, target: receiver, selector: #selector(TimerReceiver.periodic), userInfo: nil, repeats: true)
Much nicer in Swift 3 and iOS 10/macOS 10.12:
let timer = Timer.scheduledTimer(withTimeInterval: 5, repeats: true) { (_) in
DispatchQueue.global(qos: .background).async {
print("\n Doing calculations\n")
DispatchQueue.main.async {
print("\n !!! UPDATING UI !!!\n")
}
}
}