12

in my app i have some NSOperation that update some core data element from a online database, sometime the update require some minute, and when the screen of iPhone lock, the app enter in the background mode, and this update is stopped, so i have to reopen the app to continue the update, so i have search a lot on stack overflow and i have find some information about:

beginBackgroundTaskWithExpirationHandler

that is a method from apple that let continue some task also when the app is in the background mode, and i have do this:

- (void)applicationDidEnterBackground:(UIApplication *)application
{

UIApplication  *app = [UIApplication sharedApplication];
UIBackgroundTaskIdentifier bgTask;

bgTask = [app beginBackgroundTaskWithExpirationHandler:^{
    [app endBackgroundTask:bgTask];
}];
}

and now the app continue the task in the background, and seems that all works fine, so my question is, this method i use is safe? or there is a better mode?

thanks

Piero
  • 9,173
  • 18
  • 90
  • 160
  • 1
    Check the answer posted here.. http://stackoverflow.com/questions/12071726/how-to-use-beginbackgroundtaskwithexpirationhandler-for-already-running-task-in – iDev Nov 26 '12 at 23:54

1 Answers1

16

That's not how you do this. Any code that you want to run in the background must be wrapped properly. Something like this:

- (void)someMethodToKeepRunningInBackground {
    UIBackgroundTaskIdentifier taskId = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^(void) {
        // Uh-oh - we took too long. Stop task.
    }];

    // Perform task here        

    if (taskId != UIBackgroundTaskInvalid) {
        [[UIApplication sharedApplication] endBackgroundTask:taskId];
    }
}

You don't do anything in the UIApplicationDelegate applicationDidEnterBackground: method.

Any task that is wrapped inside the "background task" calls will be allowed to keep running when the app enters the background.

Here's the really important part - the task only gets 10 minutes maximum. If it is still running after 10 minutes your app will be terminated. The expiration handler gives you a few seconds to cleanly end the task before the app is terminated uncleanly.

rmaddy
  • 314,917
  • 42
  • 532
  • 579
  • yes, i searching on the web i thought that the solution was that you just wrote, but the code i wrote in my question works, i don't know how, but if i start the update, then i press the home button, when i open the app a few minute later the update is correctly finished, how do you explain this? – Piero Nov 26 '12 at 23:49
  • The code you posted works but it's wasting resources. As written, your code tells the OS that every time the app enters the background that it should be given the full 10 minutes to stay alive in the background. And when the time runs out, you tell the OS to stop the background activity. So your app is sitting active in the background for 10 full minutes every time it goes to the background, no matter how little time it actually needs to complete its process. Your app is needlessly taking away resources from other app during this time. It works, but it's a bad approach. – rmaddy Nov 26 '12 at 23:53
  • ok now i understand thanks, so in every part of code i want (not necessarily in the didenterbackground method) i use the code you write in the solution, and i have to write the code that need to peform also in the bacgkround mode after between the //Perferom task here and if(taskId != UIBackgroundTaskInvalid)....right? – Piero Nov 26 '12 at 23:56
  • Correct. You could create a single helper method that takes a block argument. Then you execute the block where is says `// Perform task here`. – rmaddy Nov 26 '12 at 23:57
  • i have to call something like this: CheckForUpdate *checkUpdate = [[CheckForUpdate alloc] init]; [sectionCheckUpdateQueue addOperation:checkUpdate]; where CheckForUpdate is a NSOperation,that check for update and if found some update create another nsoperation, i can just write that two line after //Perform task here? or i have necessarily write a block? – Piero Nov 27 '12 at 00:00
  • If you are using an operation queue then it's trickier. You don't want to call `endBackgroundTask:` until all of the queue's operations are complete. – rmaddy Nov 27 '12 at 00:01
  • That's a completely different question. Accept this answer and research your new question or ask a new question here on SO. You now need to know how to run code when all operations on an operation queue are complete. – rmaddy Nov 27 '12 at 00:05
  • if you want take a look i have create a new answer: http://stackoverflow.com/questions/13575484/check-when-two-nsoperationqueue-have-finished-to-call-endbackgroundtask-for-stop – Piero Nov 27 '12 at 00:40