This is pretty easy to verify, so I just did (on iPhone 4S running iOS 6.1.3) using the code that I paste at the end that runs the background job in the delegate method applicationDidEnterBackground . <ears>
The result is amazing. When a user exits the application by clicking the "Home" button, then manually kills the application (double-clicking "Home", moving things to jigging mode and clicking the close icon of the application), the following will happen:
applicationWillTerminate .- When
applicationWillTerminate completes, background execution completes no matter how long the background task runs. The application was killed.
BUT..
If you arrange things so that applicationWillTerminate does not exit after the call, as in my code below, the following happens: at least in my test setup - when the application manually kills:
- The background task of the application continues to run in the background .
- Even when the execution time of the highlighted background has expired, the background task continues to run, like the code in
applicationWillTerminate , until this method exits.
This is clearly a mistake - you cannot continue to execute the code forever - and I will not rely on the fact that it always works. But those who used various hacks around playing sound in the background to keep the application alive might want to explore. I would be interested if other people try the code on different versions / devices of iOS 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
source share