Saving only one background task

I am developing an application that uses background tasks to track a user's position every 20 seconds. Everything is fine, except that when I enter the application in the background, new background tasks are created, so that I can end up with several running background tasks. I tried to add [[UIApplication sharedApplication] endBackgroundTask:bgTask]; in applicationWillEnterForeground , but do nothing. The fact is that I want to cancel / disable all running background tasks when I enter the application and create a new one when I enter the background mode, or so that only one background task is executed.

 - (void)applicationDidEnterBackground:(UIApplication *)application { [self runBackgroundTask:10]; } -(void)runBackgroundTask: (int) time{ //check if application is in background mode if ([UIApplication sharedApplication].applicationState == UIApplicationStateBackground) { __block UIBackgroundTaskIdentifier bgTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{ [[UIApplication sharedApplication] endBackgroundTask:bgTask]; bgTask = UIBackgroundTaskInvalid; }]; dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{ NSTimer* t = [NSTimer scheduledTimerWithTimeInterval:time target:self selector:@selector(startTracking) userInfo:nil repeats:NO]; [[NSRunLoop currentRunLoop] addTimer:t forMode:NSDefaultRunLoopMode]; [[NSRunLoop currentRunLoop] run]; }); } } -(void)startTracking{ //Location manager code that is running well } 
+1
ios
source share
2 answers

I suggest changing the UIBackgroundTaskIdentifier as a property of the application delegate class and initializing it to UIBackgroundTaskInvalid in didFinishLaunchingWithOptions . Then, in your other delegated application methods, you can simply check the value of this property to determine if there is a background task identifier to complete or not.

-

Unrelated observation, but you don't need this runloop stuff. Just mark the timer on the main thread / runloop (using scheduledTimerWithTimeInterval ) and get rid of all this runloop stuff (because you already added it to the main runloop and this runloop is already running).

For example, suppose I wanted to do something every 10 seconds while the application was in the background, I would do something like the following:

 @interface AppDelegate () @property (atomic) UIBackgroundTaskIdentifier bgTask; @property (nonatomic, weak) NSTimer *timer; @end @implementation AppDelegate - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { self.bgTask = UIBackgroundTaskInvalid; return YES; } - (void)applicationDidEnterBackground:(UIApplication *)application { self.bgTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{ if (self.bgTask != UIBackgroundTaskInvalid) { [[UIApplication sharedApplication] endBackgroundTask:self.bgTask]; self.bgTask = UIBackgroundTaskInvalid; } }]; self.timer = [NSTimer scheduledTimerWithTimeInterval:10 target:self selector:@selector(startTracking) userInfo:nil repeats:YES]; } - (void)applicationWillEnterForeground:(UIApplication *)application { // invalidate the timer if still running [self.timer invalidate]; // end the background task if still present if (self.bgTask != UIBackgroundTaskInvalid) { [[UIApplication sharedApplication] endBackgroundTask:self.bgTask]; self.bgTask = UIBackgroundTaskInvalid; } } - (void)startTracking{ NSLog(@"%s", __PRETTY_FUNCTION__); } 

Now, in your code example, the timer was not a repeating timer, so if you only wanted to start the timer once, set repeats to NO , but then make sure startTracking then the background task ended (it makes no sense to keep the application alive if you don’t are going to do anything else).

BTW, make sure that you run this code on the device and do not run it from Xcode (since it is tied to Xcode, it changes the background behavior of applications).

+2
source share

Specify the background mode of the location Use NSTimer in the background using UIApplication:beginBackgroundTaskWithExpirationHandler: In case n less than UIApplication: backgroundTimeRemaining, it will work fine, if n larger, the location manager must be enabled (and disabled) yet times until there is no time left to avoid the background task killed.

This works because the location is one of three allowed types of background execution.

Note. Some time was lost checking this in the simulator, where it does not work, works fine on the phone.

+1
source share

All Articles