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).
Rob
source share