GCD Dispatched Operation Not Running When App is Placed in Background - ios

I launch a method that is, essentially, an endless loop using dispatch_queue_create and then dispatch_async (and then the code-loop is inside the dispatched block).
The loop runs perfectly. However, when the application gets backgrounded, it pauses. Then it restarts when the app takes the foreground.
How can I prevent this from happening? I've been looking here but it seems that the priority is not one of the things I can choose.

Use the -[UIApplication beginBackgroundTaskWithExpirationHandler:] method to start a background task. The OS will give you ten minutes and call the expirationHandler block when it ends.
This method will return UIBackgroundTaskInvalid if the device can't run code in background or the task id that you must use to end it otherwise.
You can (and should) end it sooner by calling -[UIApplication endBackgroundTask];
You can probably start a task in the beginning of your block and end it when it ends, if it is a endless loop just start a task in the applicationWillResignActive method and end it on applicationDidBecomeActive. But remember, you only have ten minutes, to have more time your app would have to use location, audio, or voip.

Related

Will a background thread that receives a return eventually close itself?

It looks like if a background thread is running when you hit the home button, things are suspended and then resumed when reopening the app. I simply want things to stop when the home button is pressed so that on resume, the user can start things from the beginning. After doing some research, it looks like a simple bool flag to periodically check is the way to go. My question, is the part after that. I have the flag part working using some of the notifications like UIApplicationWillResignActiveNotification, but my question is what action to take to actually stop things. I can do a simple return to stop things, but how does that affect the thread itself? As a general question, if nothing is running, or it gets to the end of the code, will the thread close itself? Or is some sort of explicit exit call needed? In my rough testing, that thread seems to go away, but I wasn't sure.
If you have a thread whose entry point returns, your thread will close. If you install a runloop, your thread may never close, depending on your implementation. In any case, when an app enters background, the main thread is allowed to complete the current runloop run and then the app is suspended. All other threads are suspended also. Once your app returns to the foreground, or when woken up in the background under certain circumstances, your thread will resume work until you end the entry point, suspend it or your app is suspended again.
This is a simplification, of course. In some instances, threads are reused, even if your provided entry point returns. This is the case of thread pools, GCD, etc. In these cases, a thread may appear as alive, but it is actually suspended and takes little resources.

how to prevent main thread ios from killing background thread

I have a method in my AppDelegate that saves a NSManagedObjectContext passed as a parameter. This method may be called on either the main thread or a background thread, and I want to ensure that when this method is called the main thread doesn't kill it halfway through when the user terminates the program or what have you. How do I prevent the main thread from killing this thread when this method is being executed?
I also want to do this for writing data to a plist file -- this also may happen outside of the main thread.
I am doing all my background work by way of GCD and dispatch_async
Brad Larson had some suggestions on this post that should help you.
In your appDelegate, when your app is getting pushed to the background, it calls applicationDidEnterBackground. From this routine, you can see if your method is currently in progress, and can behave accordingly.
Depending on how long your task takes to run there are two options:
If it will take significantly less than 5 seconds, you can just have your applicationDidEnterBackground wait until your task is completed before releasing. If you take longer than 5 seconds, your app will just get force-killed.
If it could be a while, you can try beginBackgroundTaskWithExpirationHandler: to start a background task that finishes off your task.

How much time do I have after applicationDidEnterBackground invoked?

I want to send a timestamp to a remote server, and wait for the callback of success, then store the timestamp locally, if remote server did not respond.
Is it something that I could put into applicationDidEnterBackground implementation?
According to iOS Developer Library UIApplicationDelegate Protocol Reference
Your implementation of this method has approximately five seconds to
perform any tasks and return. If you need additional time to perform
any final tasks, you can request additional execution time from the
system by calling beginBackgroundTaskWithExpirationHandler:. In
practice, you should return from applicationDidEnterBackground: as
quickly as possible. If the method does not return before time runs
out your app is terminated and purged from memory.
You should perform any tasks relating to adjusting your user interface
before this method exits but other tasks (such as saving state) should
be moved to a concurrent dispatch queue or secondary thread as needed.
Because it's likely any background tasks you start in
applicationDidEnterBackground: will not run until after that method
exits, you should request additional background execution time before
starting those tasks. In other words, first call
beginBackgroundTaskWithExpirationHandler: and then run the task on a
dispatch queue or secondary thread.
So you have approximately 5 seconds to perform any tasks and return in "applicationDidEnterBackground" methods.
If you want to do any network stuff before going to the background, you should ask for extra time with beginBackgroundTaskWithExpirationHandler:.
You can do that in dispatch_async and you can wait the server answer and do something with your data, but you can't stop the enter background...
try this code
dispatch_queue_t savingQueue = dispatch_queue_create("savingQue", NULL);
dispatch_async(savingQueue, ^{
//do something in bg....
dispatch_async(dispatch_get_main_queue(), ^{
});
});
dispatch_release(savingQueue);

On iOS, can you begin work on the background thread before applicationDidEnterBackground is called?

I'm updating some content in my app and I want that to finish up when the user switches out of the app. It seems like I have to stop my currently-running update and start another one in the applicationDidEnterBackground method. It would be much more convenient if I could mark some work as something I want to run in the background before that method is called.
Here's the scenario:
I'm trying to update content and start running a SQL update that takes a bit of time. (More than the five seconds you have to return from applicationDidEnterBackground.)
The user leaves the app. The current update is suspended, but I really want it to finish.
I can start a new update which picks up where the other left off, but if the user switches back into the app I have SQL-level concurrency issues.
Is the only option to break down the SQL queries to smaller batches so I can switch over cleanly in the applicationDidEnterBackground callback? It almost doubles the execution time. (I'm not worried about the OS killing my background task, resume is handled fine.)
Ideally I'd be able to have the existing work continue seamlessly in the background (at the pleasure of the OS), is that possible? Are there better options?
(I've read the Programming Guide's section on executing background tasks.)
You can continue to run your current threads. You don't have to stop any of them and start new one.
The only thing which you need to do, if to use beginBackgroundTaskWithExpirationHandler (as proxi mentioned) when you entering background and use endBackgroundTask when you are done. This method gives your application up to 10 minutes of execution. UI of your application won't be accessible (since a user switched to another app), but all threads of your app will continue to run. System will pause all threads when your will do endBackgroundTask or 10 minutes will expire.
I would organize it like this
Have you processing threads running
In applicationDidEnterBackground call beginBackgroundTaskWithExpirationHandler.
Save UIBackgroundTaskIdentifier somewhere accessbile.
At the end of your processing thread, check whether UIBackgroundTaskIdentifier isn't 0 and if it's not, call endBackgroundTask. Set UIBackgroundTaskIdentifier to zero.
If I understand right, you just have to wrap your long-running operation into beginBackgroundTaskWithExpirationHandler block. See the method's documentation for details on how to use it.

Perform selector just after application:didFinishLaunchingWithOptions?

I need to upload some left-over data to server in application:didFinishLaunchingWithOptions, but it takes some time and eventually the app may be killed as it cannot finish launching in time, so I used:
[myObject performSelector:withObject:afterDelay:]
with 0.2f delay, to let application:didFinishLaunchingWithOptions finish, but it does not look like a good idea, so I wonder is there a way I can perform the selector just after application:didFinishLaunchingWithOptions?
I know there are applicationDidBecomeActive but I need it to be executed in application:didFinishLaunchingWithOptions.
If you use a delay of 0, it will be executed as soon as control returns to the runloop.
However, if this is blocking for too long in appDidFinishLaunching, then it will also block no matter when you run it. You really should move this code to a background thread. Synchronous network access on the main thread is never a good idea.

Resources