Apple's background execution example for ios - ios

Apple gives this of background execution:
- (void)applicationDidEnterBackground:(UIApplication *)application
{
bgTask = [application beginBackgroundTaskWithName:#"MyTask"
expirationHandler:^{
// Clean up any unfinished task business by marking where you
// stopped or ending the task outright.
[application endBackgroundTask:bgTask];
bgTask = UIBackgroundTaskInvalid;
}];
// Start the long-running task and return immediately.
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// Do the work associated with the task, preferably in chunks.
[application endBackgroundTask:bgTask];
bgTask = UIBackgroundTaskInvalid;
});
}
This example has never made much sense to me and I've seen it copied to numerous background application examples.
The first thing that doesn't make sense are these two lines in the expirationHandler:
[application endBackgroundTask:bgTask];
bgTask = UIBackgroundTaskInvalid;
It seems like bgTask won't have a value when captured in the block. The compiler complains as such. Then below in the dispatch_async the sample shows the same two lines. I would expect it in the dispatch_async but not in the block. Can anyone explain why we have these lines in the block?
Also the documentation per beginBackgroundTaskWithName says "Marks the beginning of a new long-running background task." How exactly is it doing this? What defines the task? Is it any code that follows in the block scope?

bgTask = [application beginBackgroundTaskWithName:#"MyTask" expirationHandler:]
tells iOS that your application is starting a new background task. iOS doesn't care which code comprises the task, it just knows that it needs to give your app more time to execute in the background.
After this line executes, bgTask will contain the new background task identifier.
When your background task is complete, you then call [application endBackgroundTask:bgTask]; and iOS knows that your app has finished the specified background task and may not need any more background execution time (You may still have other background tasks initiated by beginBackgroundTaskWithName:expirationHandler outstanding).
The line:
bgTask = UIBackgroundTaskInvalid;
is just housekeeping; If you omit this line nothing bad will happen, but bgTask will contain an invalid identifier.
If you don't call endBackgroundTask before your app's background time expires, then then expiration handler block will be invoked.
In the expiration handler bgTask will have the value that was assigned when you called beginBackgroundTaskWithName:expirationHandler, so this is what is passed to endBackgroundTask and again assigning UIBackgroundTaskInvalid is just housekeeping

Related

backgroundTask not finishing in iOS

I have the following code which makes a call to the server, before the app is about to exit. My problem is, that the code sometimes works, sometimes not. Mostly not. Here is the code:
//Set the user as in-active if app is force closed
- (void)applicationWillTerminate:(UIApplication *)application {
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
NSLog(#"called");
bgTask = [application beginBackgroundTaskWithName:#"setInActive" expirationHandler:^{
[application endBackgroundTask:bgTask];
bgTask = UIBackgroundTaskInvalid;
}];
// Start the long-running task and return immediately.
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSLog(#"disp called");
//If the app is about to exit make the user inactive
[[APIManager sharedInstance] setInActiveOnCompletion:^(BOOL finished){
[application endBackgroundTask:bgTask];
bgTask = UIBackgroundTaskInvalid;
}];
});
}
The first NSLog gets called everytime. However the second one does not. It seems as if the app does not even go into the dispatch_async method.
EDIT: So basically all I need to do is tell the server that a user has force quit the app, while that user was signed in. How could I do this?
Any ideas?
applicationWillTerminate is the last method that get called before app is being terminated!! So, you can't do anything after that, if you want to perform something in background then begin that task when you performing your operation, you can't begin background task from applicationWillTerminate because your app will not be in background after this method call!!
When your application is in the background, it is only allowed very little amount of processing, therefore using dispatch_async will not buy you much extra time. Also, Apple does not want that.

Implement updating location to server in the background mode- iOS

What I want do is:
Updating the current location of iOS device to my server periodically(every 10min), even my App is in the background mode.
What I have done:
Add the Required Background Modes in the plist; and asked requestAlwaysAuthorization.
Set background refreshing of this App in Setting.
Set a NSTimer to get the location(using CLLocationManager) periodically.
When the locationManager: didUpdateLocations:delegate called, updating location use HTTPGET to the server.
My problem:
When App is in foreground it works fine, but the update location method does not run in background, server cannot receive my location data.
Thank you.
Please check if you have enable Location in background modes from project settings -> Target -> Capabilities.
Instead of location send to server in every 10 mins , I would like to suggest you use startMonitoringVisits() and locationManager(_:didVisit:) delegate to get user location. Because your approach will be too much battery killer.
You have to register your background task with below code and then your task is finish you have to end background task
- (void)applicationDidEnterBackground:(UIApplication *)application
{
bgTask = [application beginBackgroundTaskWithName:#"MyTask" expirationHandler:^{
// Clean up any unfinished task business by marking where you
// stopped or ending the task outright.
[application endBackgroundTask:bgTask];
bgTask = UIBackgroundTaskInvalid;
}];
// Start the long-running task and return immediately.
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// Do the work associated with the task, preferably in chunks.
[application endBackgroundTask:bgTask];
bgTask = UIBackgroundTaskInvalid;
});
}
for more info: apple document

BLE background operation issue

I am trying to transfer a firmware file from my app to a wearable hardware.
it takes about some time and when my app goes in background or the lock button is pressed the firmware transfer process discontinues.
ideally it should continue to transfer the firmware. I am using this method to continue the process in background and also also have declared the support for the background modes.
- (void)applicationDidEnterBackground:(UIApplication *)application {
bgTask = 0;
bgTask = [application beginBackgroundTaskWithName:#"MyTask" expirationHandler:^{
// Clean up any unfinished task business by marking where you
// stopped or ending the task outright.
//[application endBackgroundTask:bgTask];
bgTask = UIBackgroundTaskInvalid;
}];
// Start the long-running task and return immediately.
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// Do the work associated with the task, preferably in chunks.
//[application endBackgroundTask:bgTask];
bgTask = UIBackgroundTaskInvalid;
});
}
This method is not able to do the task.
However if I use this method in Appdelegate - didFinishLaunchingWithOptions it works.
But there is a trade off with putting this piece of code in the above method i.e If I am not transferring the firmware and the app goes in background then after 3 mins this piece of code removes the app and bluetooth connection breaks.
If I am not using this method at all, then the connection remains until it is broken manually but background transfer does not happen.
I have to keep both the operations simultaneously. Please suggest something as I have been for many days on this particular problem.
Thanks in advance.
Try to run your application using BackgroundModes
and remove all the codes from didEnterInbackground

ios background tasks - explain sequence of execution?

Could someone explain sequence of execution please in applicationDidEnterBackground?
UIBackgroundTaskIdentifier background_task;
background_task = [application beginBackgroundTaskWithExpirationHandler: ^ {
[application endBackgroundTask: background_task];
background_task = UIBackgroundTaskInvalid;
}];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSLog(#"\n\nRunning in the background!\n\n");
[application endBackgroundTask: background_task];
background_task = UIBackgroundTaskInvalid;
});
My understanding is
create identifier for background task and assign block that will be called once time (10 minutes or so) expires
dispatch async method, output NSLog. During this time all other methods of the app can be used
immediately after NSLog out terminate background task, not waiting for system default expiration
Specifically, after I call NSLog
[application endBackgroundTask: background_task];
background_task = UIBackgroundTaskInvalid;
task will be terminated and expirationHandler block will not be called.
I also think my understanding is incorrect...
Everything about your post is basically correct except for one important detail. None of this has anything to do with the applicationDidEnterBackground app delegate method.
Any task in your app that might take more than a couple of seconds should be wrapped inside calls to beginBackgroundTaskWithExpirationHandler and endBackgroundTask.
The whole point of wrapping code in these two methods is to notify the OS that you have some processing that needs to keep running even if the app happens to enter the background while it is running. Without these blocks, your app will be killed by the OS after only a few (10?) seconds of trying to run in the background.

Multiple beginBackgroundTaskWithExpirationHandler

If we have a long running task, we can ensure that the application doesn't quit until that task is complete by using the following piece of code:
UIApplication *app = [UIApplication sharedApplication];
bgTask = [app beginBackgroundTaskWithExpirationHandler:^{
// Clean up any unfinished task business by marking where you.
// stopped or ending the task outright.
[app endBackgroundTask:bgTask];
bgTask = UIBackgroundTaskInvalid;
}];
// Start the long-running task and return immediately.
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
// Do the work associated with the task, preferably in chunks.
[app endBackgroundTask:bgTask];
bgTask = UIBackgroundTaskInvalid;
});
In my case, the applications plist contains an entry for Application does not run in background set to YES. Now, i have a serial queue (dispatch_queue_create(..., NULL)) that logs the operations and perform them one by one. User can post many tasks at a time and it might take couple of seconds 20-30 for all of them to complete.
Now my question is, can i use beginBackgroundTaskWithExpirationHandler with my serial queue? If so, any recommendations as to how? I believe i'll have to maintain an array of UIBackgroundTaskIdentifier?
To the best of my knowledge, if the application doesn't support background processing, the application quits immediately. So, starting a background tasks is not possible.

Resources