Search code examples
iosiphoneobjective-cgrand-central-dispatchnsoperationqueue

iOS: Repeated task only when APP is active (No background)


I have found several post asking how to run background tasks. This is fine. I get it. There is a guideline from Apple and can be done only for certain types of Apps.

My use case here is the following: I want to update the contact list of a chat App only when the APP is in foreground. Hence I can start/pause/resume when the App goes respectively in the following states: didBegan, didEnterBackground, didResumeFromBackground.

How can I achieve this using GCD?

In other words, how can I schedule an asynchrounous task in a repeated way and to be called only every so often (say every 0.5 seconds)? Is there a good implementation using NSOperationQueue?

EDIT 2: Tasks I want to perform:

1: GET from a webservice API a JSON data object containing information on the contacts (online status, device, lastseen at)

2: GET from a webservice API a JSON data object containing messages to the user

EDIT: NSOperation documentation defines an operation as something that can be used only as "single shot", hence creating a recursive operation is probably not the best way to solve this.


Solution

  • Here is some code on how to achieve this with a timer and both GCD and an operation queue.

    NSOperationQueue* queue = [NSOperationQueue new];
    [queue setMaxConcurrentOperationCount:1]; //Make serial.
    //dispatch_queue_t queue = dispatch_queue_create("queue", NULL); //Serial queue.
    

    Gentlemen, start your timers:

    [NSTimer scheduledTimerWithTimeInterval:0.0 target:appDelegate selector:@selector(timerTicked:) userInfo:nil repeats:NO]; //Start a timer with 0 so it ticks immediately.
    

    Now in the method:

    - (void)timerTicked:(NSTimer*)timer
    {
        NSLog(@"Timer ticked!");
        void (^block)() = ^{
            //Do what you need here.
    
            //Start a new timer.
            [NSTimer scheduledTimerWithTimeInterval:1.0 target:appDelegate selector:@selector(timerTicked:) userInfo:nil repeats:NO];
        };
    
        [queue addOperationWithBlock:block];
        //dispatch_async(queue, block);
    }
    

    I use the app delegate because timers retain the target object, so I don't want to have it in a view controller. You can schedule the next timer either right after timer tick or after the operation/task has completed, which is what I prefer to do.