Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Prevent dispatch_after() background task from being executed

This is my issue. When my application enters background I want it to perform a function after certain period of time. This is what I do:

- (void)applicationDidEnterBackground:(UIApplication *)application
{
    isRunningInBackground = YES;

    taskIdentifier = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:nil];

    int64_t delayInSeconds = 30;
    dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);
    dispatch_after(popTime, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void)
    {
        [self doSomething];
    });
}

- (void)doSomething
{
   NSLog(@"HELLO");
}

taskIdentifier variable is declared in myAppDelegate.h file like this:

UIBackgroundTaskIdentifier taskIdentifier;

Everything works as it supposed to, I see that console prints HELLO just right after 30 seconds are gone. But I don't want doSomething to be executed if the app enters foreground until 30 seconds are over. So I need to cancel it. This is how i do that:

- (void)applicationWillEnterForeground:(UIApplication *)application
{    
    isRunningInBackground = NO;
    [self stopBackgroundExecution];
}

- (void)stopBackgroundExecution
{
    [[UIApplication sharedApplication] endBackgroundTask:taskIdentifier];
    taskIdentifier = UIBackgroundTaskInvalid;
}

But unfortunately it doesn't cancel doSomething, it is still performed. What am I doing wrong? How do I cancel that function?

like image 386
Andrey Chernukha Avatar asked Sep 18 '12 10:09

Andrey Chernukha


2 Answers

Why even use GCD? You could just use an NSTimer and invalidate it when your app returns to the foregound.

like image 193
Stephen Darlington Avatar answered Sep 24 '22 21:09

Stephen Darlington


A bit different approach OK, so, with all answers collected, and possible solutions, seems like the best one for this case (preserving simplicity) is calling performSelector:withObject:afterDelay: and cancelling it with cancelPreviousPerformRequestsWithTarget: call when desired. In my case - just before scheduling next delayed call:

[NSObject cancelPreviousPerformRequestsWithTarget: self selector:@selector(myDelayedMethod) object: self];

[self performSelector:@selector(myDelayedMethod) withObject: self afterDelay: desiredDelay];
like image 12
Oleg Shanyuk Avatar answered Sep 23 '22 21:09

Oleg Shanyuk