iOS: background process and singleton - ios

In my app I should populate a core data DB and I want do it also in background
- (void)applicationDidEnterBackground:(UIApplication *)application
{
if ([[UIDevice currentDevice] respondsToSelector:#selector(isMultitaskingSupported)]) { //Check if our iOS version supports multitasking I.E iOS 4
if ([[UIDevice currentDevice] isMultitaskingSupported]) { //Check if device supports mulitasking
UIApplication *application = [UIApplication sharedApplication]; //Get the shared application instance
__block UIBackgroundTaskIdentifier background_task; //Create a task object
background_task = [application beginBackgroundTaskWithExpirationHandler: ^ {
[application endBackgroundTask: background_task]; //Tell the system that we are done with the tasks
background_task = UIBackgroundTaskInvalid; //Set the task to be invalid
//System will be shutting down the app at any point in time now
}];
//Background tasks require you to use asyncrous tasks
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
//Perform your tasks that your application requires
DBSync *sync = [DBSync sharedInstance];
[sync startDownloadDataandUpdateDB];
[application endBackgroundTask: background_task]; //End the task so the system knows that you are done with what you need to perform
background_task = UIBackgroundTaskInvalid; //Invalidate the background_task
});
}
}
}
the problem is that the method "startDownloadDataandUpdateDB" is called, but this method call other method in DBSync but these others methods don't work, I don't understand

I believe it is not really good practice to make network calls in that method.
The documentation states that you have approximately five seconds to perform any tasks and return.
You might want to take a look to beginBackgroundTaskWithExpirationHandler

Related

Can I use beginBackgroundTaskWithName for normal app processing

I have some NSOperations that are started regularly in my application. They should complete even when the the application is put to background. For this, I'm using the beginBackgroundTaskWithExpirationHandler method.
Am I supposed to use the beginBackgroundTaskWithExpirationHandler/ endBackgroundTask: every time I start my task even if the app is not going to background? Or am I supposed the call the begin/end methods only when I detected a UIApplicationDidEnterBackgroundNotification?
Option 1: Use background task every time
/**
* This method is called regularly from a NSTimer
*/
- (void)processData
{
__block UIBackgroundTaskIdentifier operationBackgroundId = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
[[UIApplication sharedApplication] endBackgroundTask:operationBackgroundId];
operationBackgroundId = UIBackgroundTaskInvalid;
}];
NSOperation *operation = ...
[self.queue addOperation:operation];
operation.completionBlock = ^{
[[UIApplication sharedApplication] endBackgroundTask:operationBackgroundId];
operationBackgroundId = UIBackgroundTaskInvalid;
};
}
Option 2: Use background task only when the application is about to go to background
/**
* This method is called regularly from a NSTimer
*/
- (void)processData
{
NSOperation *operation = ...
[self.queue addOperation:operation];
}
- (void)applicationDidEnterBackground:(NSNotification *)notification
{
__block UIBackgroundTaskIdentifier operationBackgroundId = [[UIApplication sharedApplication] beginBackgroundTaskWithName:#"EnterBackgroundFlushTask" expirationHandler:^{
[[UIApplication sharedApplication] endBackgroundTask:operationBackgroundId];
operationBackgroundId = UIBackgroundTaskInvalid;
}];
// wait for all operations to complete and then
// let UIApplication know that we are done
[[UIApplication sharedApplication] endBackgroundTask:operationBackgroundId];
}
Answering my own question. From the Apple Docs:
You do not need to wait until your app moves to the background to
designate background tasks. A more useful design is to call the
beginBackgroundTaskWithName:expirationHandler: or
beginBackgroundTaskWithExpirationHandler: method before starting a
task and call the endBackgroundTask: method as soon as you finish. You
can even follow this pattern while your app is executing in the
foreground.
Other Apple API reference:
You should call this method at times where leaving a task unfinished might be detrimental to your app’s user experience.
You can call this method at any point in your app’s execution.
Option2 is correct option.Here is code from Apple document for your reference.
- (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.
[self processData];
[application endBackgroundTask:bgTask];
bgTask = UIBackgroundTaskInvalid;
});
}
Apple developer Guide

Background timed task iOS

I'm developing an app in which I want to make a network call (syncing purpose) on an hourly basis. Even when the app is in the terminated state. How can I achieve this?
There is no UI Update involved anywhere, I just need to update local database and the cloud storage file.
developer apple BackgroundExecution
-(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;
});
}
if([[UIDevice currentDevice] respondsToSelector:#selector(isMultitaskingSupported)])
{
__block UIBackgroundTaskIdentifier background_task;
background_task = [application beginBackgroundTaskWithExpirationHandler:^ {
[application endBackgroundTask: background_task];
background_task = UIBackgroundTaskInvalid;
}];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{
while(YES)
{
[NSThread sleepForTimeInterval:your_sleep_time];
}
});
}
else
{
NSLog(#"Multitasking Not Supported");
}
We've created a new background task and add a new thread to it, so you can sleep the thread freely :)
I Hope I've help you

AVExportSession to continue in background

I am working on one application in which it requires to merge more than one videos. I am using AVExportSession to export merged video. I am also displaying progress bar for exporting video. It is running correctly.
The issue occurs when we lock the screen or put application in background mode. This time if exporting is in process, it immediately fails after putting application in background mode.
I have also tried to use background task. Check below code.
if ([[UIDevice currentDevice] respondsToSelector:#selector(isMultitaskingSupported)]) {
if ([[UIDevice currentDevice] isMultitaskingSupported]) {
UIApplication *application = [UIApplication sharedApplication];
__block 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), ^{
//START EXPORT SESSION
[exporter exportAsynchronouslyWithCompletionHandler:^
{
dispatch_async(dispatch_get_main_queue(), ^{
[self exportDidFinish:exporter];
});
}];
NSLog(#"Running in the background!");
[application endBackgroundTask: background_task];
background_task = UIBackgroundTaskInvalid;
});
}
}
But this does not seem to work. What am I doing wrong? Any help would be appreciated.
I know it is possible to run an AVExportSession in the background as I found many apps in the app store that can do this.
Thanks in advance.
replace this code for [self exportDidFinish:exporter];
[self performSelectorOnMainThread:#selector(exportDidFinish:) withObject:exporter waitUntilDone:YES];

Background Task with NSOperation and NSOperationQueue iOS

I want to upload some files which should continue even if the application goes into background.
Currently I am retrieving the files from the DB and than adding it to the Queue via NSOperation which is then starts the upload procedure.
All the files should be uploaded even if the app goes to background or foreground.
Below is the code for single task can anyone give me a hint how we can make it to work for uploading many files.
UIApplication* application = [UIApplication sharedApplication];
bgTask = [application beginBackgroundTaskWithExpirationHandler:^{
// Clean up any unfinished task business by marking where you
// stopped or ending the task outright.
[application endBackgroundTask: bgTask];
bgTask = UIBackgroundTaskInvalid;
}];
Why not try doing this? .. I haven't yet tried it out, I'll post an update after attempting this
UIApplication* application = [UIApplication sharedApplication];
bgTask = [application beginBackgroundTaskWithExpirationHandler:^{
// Clean up any unfinished task business by marking where you
// stopped or ending the task outright.
// Bring up your NSOperation queue instance here and block this thread until it is complete
[queue waitUntilAllOperationsAreFinished];
[application endBackgroundTask: bgTask];
bgTask = UIBackgroundTaskInvalid;
}];
also ensure that you have a way to cancel all these long standing operation in the background
bgTask = [application beginBackgroundTaskWithExpirationHandler:^{
// Clean up any unfinished task business by marking where you.
// stopped or ending the task outright.
[queue cancelAllOperations];
[application endBackgroundTask:endSessionTask];
bgTask = UIBackgroundTaskInvalid;
}];
Apple allows background execution if your app follows and satisfy the necessary condition.
plese refer here

Continuing a long running process in the background under iOS4

I have have an upload queue running using ASIHTTP request. When the user presses the home screen and the app goes into the background I would like this operation to continue. From the documentation I can see how I would call a new task could be called to run in the back ground, but can't quite see how I would flag an already running task to continue.
this example is bracketed for pre-4.0 compatibility:
UIApplication *app = [UIApplication sharedApplication];
if ([app respondsToSelector:#selector(beginBackgroundTaskWithExpirationHandler:)]) {
backgroundTaskIdentifier = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
dispatch_async(dispatch_get_main_queue(), ^{
if (backgroundTaskIdentifier != UIBackgroundTaskInvalid)
{
// you took too long - clean up what you can, then …
[app endBackgroundTask:backgroundTaskIdentifier];
backgroundTaskIdentifier = UIBackgroundTaskInvalid;
}
});
}];
}
// start HTTP request …
when you complete your process, you should call endBackgroundTask: to let the app know

Resources