Reputation: 739
I'm building an app with Region monitoring. It works fine in foreground but once the app is sent in background, it's not behaving as expected: it does call didEnter and didExit but as soon as it starts executing the callbacks it stops. In these callback methods i need to poll a server and persist didExitRegion and/or didEnterRegion status. As soon as I put the app in foreground again, any queued request starts and completes. Any idea? I'm using ios5.1 and ios6 on iphone 4
Upvotes: 0
Views: 946
Reputation: 1332
When you get called in the background in
- (void)locationManager:(CLLocationManager *)manager didEnterRegion:(CLRegion *)region
(or ...exit)
just setup whatever you need for the server call (variables, payload for the server etc etc). Before the actual sending start a
self.bgTaskId = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
[[UIApplication sharedApplication] endBackgroundTask:self.bgTaskId];
self.bgTaskId = UIBackgroundTaskInvalid;
somelogger(@"ran out of time for background task");
// remember that we failed for the next time the app comes to the foreground
}];
Then do the actual sending with the HTTP framework of your choice and in the completion handlers reset the background task with
[[UIApplication sharedApplication] endBackgroundTask:self.bgTaskId];
Example using AFNetworking:
[self.httpClient postPath:@"state" parameters:@{@"abc": abc, @"value": val, @"h": h, @"app":myAppName , @"version": myAppVersion }
success:^(AFHTTPRequestOperation *operation, id responseObject) {
if (operation.response.statusCode != 200) {
DDLogVerbose(@"response was not 200. error: %i", operation.response.statusCode);
} else {
DDLogVerbose(@"success");
}
[[UIApplication sharedApplication] endBackgroundTask:self.bgTaskId];
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
DDLogVerbose(@"request error %@, current retry count %d", error, retryCount );
// start our own retry mechanism
if (retryCount < MAX_RETRIES) {
retryCount++;
double delayInSeconds = RETRY_INTERVAL * (1 + (double)retryCount/10);
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
// try again
});
} else {
// final
[[UIApplication sharedApplication] endBackgroundTask:self.bgTaskId];
// remember failure when app comes back to foreground
}
}];
I am using a
@property (assign, nonatomic) UIBackgroundTaskIdentifier bgTaskId;
to store the background identifier.
The whole mechanism is explained in http://developer.apple.com/library/ios/#documentation/iphone/conceptual/iphoneosprogrammingguide/ManagingYourApplicationsFlow/ManagingYourApplicationsFlow.html#//apple_ref/doc/uid/TP40007072-CH4-SW28
Upvotes: 2
Reputation: 1596
If you havent already add 'location' to the UIBackgroundModes of your Info.plist. As a second idea I'd use AFNetworking which is widely popular and has backgrounding support. That means it will deal with setting up the parameters to tell the OS that it will "finish this thing before I go back to sleep".
Upvotes: -1
Reputation: 28767
you have to request additional time if you want to stay alive. see applle docu on background mode. There is a method for that. generally you are not "allowed" to stay active in background for any task. only for specific ones, like GPS. try to request additional background time after each region update.
Upvotes: 0