I have a task that needs to be performed every 1 second. Currently I have an NSTimer firing repeatedly every 1 sec. How do I have the timer fire in a background thread (no
Swift only (although can probably be modified to use with Objective-C)
Check out DispatchTimer
from https://github.com/arkdan/ARKExtensions, which "Executes a closure on specified dispatch queue, with specified time intervals, for specified number of times (optionally). "
let queue = DispatchQueue(label: "ArbitraryQueue")
let timer = DispatchTimer(timeInterval: 1, queue: queue) { timer in
// body to execute until cancelled by timer.cancel()
}
If you want to go pure GCD and use a dispatch source, Apple has some sample code for this in their Concurrency Programming Guide:
dispatch_source_t CreateDispatchTimer(uint64_t interval, uint64_t leeway, dispatch_queue_t queue, dispatch_block_t block)
{
dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
if (timer)
{
dispatch_source_set_timer(timer, dispatch_walltime(NULL, 0), interval, leeway);
dispatch_source_set_event_handler(timer, block);
dispatch_resume(timer);
}
return timer;
}
Swift 3:
func createDispatchTimer(interval: DispatchTimeInterval,
leeway: DispatchTimeInterval,
queue: DispatchQueue,
block: @escaping ()->()) -> DispatchSourceTimer {
let timer = DispatchSource.makeTimerSource(flags: DispatchSource.TimerFlags(rawValue: 0),
queue: queue)
timer.scheduleRepeating(deadline: DispatchTime.now(),
interval: interval,
leeway: leeway)
// Use DispatchWorkItem for compatibility with iOS 9. Since iOS 10 you can use DispatchSourceHandler
let workItem = DispatchWorkItem(block: block)
timer.setEventHandler(handler: workItem)
timer.resume()
return timer
}
You could then set up your one-second timer event using code like the following:
dispatch_source_t newTimer = CreateDispatchTimer(1ull * NSEC_PER_SEC, (1ull * NSEC_PER_SEC) / 10, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// Repeating task
});
making sure to store and release your timer when done, of course. The above gives you a 1/10th second leeway on the firing of these events, which you could tighten up if you desired.
This should work,
It repeats a method every 1 second in a background queue without using NSTimers :)
- (void)methodToRepeatEveryOneSecond
{
// Do your thing here
// Call this method again using GCD
dispatch_queue_t q_background = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0);
double delayInSeconds = 1.0;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);
dispatch_after(popTime, q_background, ^(void){
[self methodToRepeatEveryOneSecond];
});
}
If you are in the main queue and you want to call above method you could do this so it changes to a background queue before is run :)
dispatch_queue_t q_background = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0);
dispatch_async(q_background, ^{
[self methodToRepeatEveryOneSecond];
});
Hope it helps
class BgLoop:Operation{
func main(){
while (!isCancelled) {
sample();
Thread.sleep(forTimeInterval: 1);
}
}
}