Timer in another thread in Objective - C
Asked Answered
T

2

9

I have to define method which should be invoked periodically with some time interval. I need to invoke it in another thread (NOT main thread), because this method is used to get information from external API and sync data in core data.

How do I define this method to not block main thread?

Toomin answered 4/2, 2014 at 21:27 Comment(0)
P
19

Unless you have a specific need for timers, you can use Grand Central Dispatch.

The following snippet will execute a block after 2 seconds, on the default priority concurrent queue (i.e a background thread). You can change the priority of the queue if you see fit, but unless you're dealing with lots of different operations on concurrent queues, default will suffice.

double delayInSeconds = 2.0;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));

dispatch_after(popTime, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void){
    // Your code here
});

If you're wanting to call this repeatedly, then you can use dispatch_source_set_timer to set a recurring execution. The jist of it is below:

// Create a dispatch source that'll act as a timer on the concurrent queue
// You'll need to store this somewhere so you can suspend and remove it later on
dispatch_source_t dispatchSource = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0,
                                                          dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)); 

// Setup params for creation of a recurring timer
double interval = 2.0;
dispatch_time_t startTime = dispatch_time(DISPATCH_TIME_NOW, 0);
uint64_t intervalTime = (int64_t)(interval * NSEC_PER_SEC);
dispatch_source_set_timer(dispatchSource, startTime, intervalTime, 0);

// Attach the block you want to run on the timer fire
dispatch_source_set_event_handler(dispatchSource, ^{
    // Your code here
});

// Start the timer
dispatch_resume(dispatchSource);

// ----

// When you want to stop the timer, you need to suspend the source
dispatch_suspend(dispatchSource);

// If on iOS5 and/or using MRC, you'll need to release the source too
dispatch_release(dispatchSource);
Poche answered 4/2, 2014 at 21:34 Comment(4)
Hi thanks for this, can I confirm that whatever is in the block will not run on the main thread? Ie. They will not be interrupted by UI actions.Lantz
Generally, anything you do within the block will stay on the queue you've dispatched it to. But, if you call something within the block that subsequently dispatches something else to the main thread, then that new dispatch will occur on the main thread.Poche
Ok tried it works great. Just like to add to the above - you need to put dispatch_source_t dispatchSource as a member variable outside of the code here (assuming its a function) if you want the code in the dispatch_source_set_event_handler to work. dispatch_cancel(dispatchSource) is also useful to stop the timer before starting another with dispatch_source_create. Thanks for this!Lantz
The reason for the above is that if not defined outside of scope, dispatchSource falls out of scope when the function it is defined in is exited.Lantz
T
1

Use NSRunLoop and NSTimer for work

NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(timer) userInfo:nil repeats:NO];

[[NSRunLoop mainRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
Televisor answered 5/2, 2014 at 1:40 Comment(3)
The main run loop is for the main thread; the question asks to run in a background thread.Poche
This is incorrect, I am using this it runs on the main thread.Lantz
this beats the OP's intention NOT to burden the main thread with their work.Dyaus

© 2022 - 2024 — McMap. All rights reserved.