JHSnows
JHSnows

Reputation: 431

What happens if the user closes an app that is already in the background?

During a background task execution what will happen if the user kills the app (which already is in background mode)?

Picture this:

The app starts task X (with 10 min background support and a expiration handler that has to be called). Then, the app goes to background and the user kills the app.

I'm confused on what will happen to task X after the app is killed. Does it still have that background time to execute? Does the expiration handler ever gets called?

Upvotes: 4

Views: 1492

Answers (3)

davidf2281
davidf2281

Reputation: 1328

This is pretty easy to test, so I just did (on an iPhone 4S running iOS 6.1.3) using code I'll paste at the end, which starts a background task in the app delegate's applicationDidEnterBackground method.

The result is surprising.

When the user exits the app by clicking the Home button, then manually kills the app (by double-clicking Home, putting things in jiggy mode and hitting the app's close icon) the following occurs:

  1. applicationWillTerminate is called.
  2. When applicationWillTerminate exits, background execution is terminated, regardless of how much execution time the background task had left. The app has been killed.

HOWEVER..

If you arrange things so that applicationWillTerminate doesn't exit after being called, as in my code below, the following happens -- at least it does on my test setup -- when the app is manually killed:

  1. The app's background task continues to run in the background.
  2. Even when the allocated background execution time has expired, the background task continues to run, as does the code in applicationWillTerminate, until that method exits.

This is clearly a bug -- you shouldn't be able to continue to run code forever -- and I wouldn't rely on it always working. But those who've been using various hacks around playing audio in the background to keep an app alive might want to investigate. I'd be interested if other people try the code on different iOS versions/devices and get the same results.

Code for AppDelegate.m in my test project:

//
//  BTAppDelegate.m
//  BackgroundTest
//
//  Created by David Fearon on 07/05/2013.
//  Copyright (c) 2013 David Fearon. All rights reserved.
//

#import "BTAppDelegate.h"

@implementation BTAppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    NSLog(@"application didFinishLaunchingWithOptions called");
    // Override point for customization after application launch.

    return YES;
}

- (void)applicationWillResignActive:(UIApplication *)application
{
    NSLog(@"applicationWillResignActive: called");

}

- (void)applicationDidEnterBackground:(UIApplication *)application
{
    NSLog(@"applicationDidEnterBackground: called");


    UIApplication* thisApp = [UIApplication sharedApplication];
    UIBackgroundTaskIdentifier __block task = [thisApp beginBackgroundTaskWithExpirationHandler:^{
    }];

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        [self printTimeRemaining];
        while(YES) {
            [NSThread sleepForTimeInterval:1.0];
            [self printTimeRemaining];
        }
        //[thisApp endBackgroundTask:task];
    });

}


-(void)printTimeRemaining{
    NSLog(@"Background task time remaining: %f", [[UIApplication sharedApplication] backgroundTimeRemaining]);
}

- (void)applicationWillEnterForeground:(UIApplication *)application
{
    NSLog(@"applicationWillEnterForeground: called");

}

- (void)applicationDidBecomeActive:(UIApplication *)application
{
    NSLog(@"applicationDidBecomeActive: called");

}

- (void)applicationWillTerminate:(UIApplication *)application
{
    NSLog(@"applicationWillTerminate: called");

    while(YES) {
        [NSThread sleepForTimeInterval:1.0];
        NSLog(@"Still executing code in applicationWillTerminate.");
    }

}

@end

Upvotes: 2

msk
msk

Reputation: 8905

Ok so this is the result

In this case OS will send a SIGKILL signal to your app's process and applicationWillTerminate method is not called.

Below is just my interpretation from Apple docs, guess work and Google results.

In such case below method of your application delegate will get called

- (void)applicationWillTerminate:(UIApplication *)application

Quote from Apple Docs

For applications that do not support background execution or are linked against iOS 3.x or earlier, this method is always called when the user quits the application. For applications that support background execution, this method is generally not called when the user quits the application because the application simply moves to the background in that case. However, this method may be called in situations where the application is running in the background (not suspended) and the system needs to terminate it for some reason.

So you have to UIApplicationExitsOnSuspend value to YES in your plist file otherwise there is no guarantee that applicationWillTerminate: will ever get called. That is why the doc has may used in.

I dont think expiration handler block will be called, though I am not sure.

Upvotes: 1

matt
matt

Reputation: 535304

If the app is "already in background", the user has already "closed the app"! So what can your question mean? You've already gone into the background, and if you called beginBackgroundTaskWithExpirationHandler: as you did so, things proceed normally.

Do you mean the user forcibly kills the app in the background, by summoning the "recent apps" interface and going into jiggy mode and deleting the app from the "recent apps" interface? Then the app is summarily killed; you get no notification and whatever you were doing is interrupted.

Moreover, the only thing the expiration handler block is supposed to do is call endBackgroundTask:. If you are summarily killed, the fact that you are unable to make this call is unimportant!

Upvotes: 3

Related Questions