NSOperation queue not working in background - ios

I want that my image uploading should work in background.
I have enable Background Modes and made a Operation queue to upload multiple files at a time to server.
But as soon as put app in background NSOperation pauses, and restart again when in foreground.
I have also added beginBackgroundTaskWithExpirationHandler before starting my operation queue and endBackgroundTask when all images get uploaded in server.
This makes all images upload to server also while app is in background, but my app is getting killed, I don't want the app to get killed .
Please suggest some solution to my problem .

Your app has limited time when running in background. After its allotted time has expired it gets killed.
According to Apple:
In your own expiration handlers, you can include additional code needed
to close out your task. However, any code you include must not take too
long to execute because, by the time your expiration handler is called,
your app is already very close to its time limit. For this reason,
perform only minimal cleanup of your state information and end the
task.
Also get the value of the backgroundTimeRemaining property to check the remaining time.

Related

Application does not run in background after 5 minutes. (iOS)

I'm working on an iOS application and I want the app to terminate after hanging in the background for more than 5 minutes and when the user opens the app again it should display the login. For now the app terminates immediately when it reaches the background and the login screen when the user re-opens the app. I did this by adding a property called "Application does not run in background" to the info.plist file and I set the value to "YES". As I mentioned at the start what I want to do is to terminate the app after 5 minutes in background but not immediately. And the login screen appearing after the user re-opens the app is working fine.
Application does not run in background property in info.plist
I guess you this is managed by the operating system that for how long the app runs in the background, and the os terminates it when it require resources to get free.
A workaround that could be done is, store the time value in UserDefaults whenever the app goes to background, and whenever the app comes foreground, check for the previous time value. If the difference is greater than 5 minutes, you may direct to login.
You can request background time when you are told that you are being suspended. I believe the max you will get is 3 minutes, not 5. That will prevent your app from being terminated, and keep your app getting CPU time during that time. (Which will use extra battery power.) You will get a notice when that time expires, and you can save your app state and log off at that point.
Search on "Extending Your App's Background Execution Time" in the Xcode help system or Apple's docs for more information. The overview section of that document reads:
Overview
Extending your app’s background execution time ensures that you have adequate time to perform critical tasks. For tasks that require more background time, use Background Tasks.
When your app moves to the background, the system calls your app delegate’s applicationDidEnterBackground(_:) method. That method has five seconds to perform any tasks and return. Shortly after that method returns, the system puts your app into the suspended state. For most apps, five seconds is enough to perform any crucial tasks, but if you need more time, you can ask UIKit to extend your app’s runtime.
You extend your app’s runtime by calling the beginBackgroundTask(withName:expirationHandler:) method. Calling this method gives you extra time to perform important tasks. (You can find out the maximum background time available using the backgroundTimeRemaining property.) When you finish your tasks, call the endBackgroundTask(_:) method right away to let the system know that you are done. If you do not end your tasks in a timely manner, the system terminates your app.
The key bits of that are:
"When your app moves to the background, the system calls your app delegate’s applicationDidEnterBackground(_:) method."
And "You extend your app’s runtime by calling the beginBackgroundTask(withName:expirationHandler:) method"
Note that you should really implement an app level "heartbeat" where the app sends periodic "I'm still here" messages to the server to keep the user logged in. Your server should log the user off if they miss more than one heartbeat message.

iOS : Use of HKObserverQuery's background update completionHandler

HKObserverQuery has the following method that supports receiving updates in the background:
- initWithSampleType:predicate:updateHandler:
The updateHandler has a completionHandler which has the following documentation:
This block is passed to the update handler. You must call this block
as soon as you are done processing the incoming data. Calling this
block tells HealthKit that you have successfully received the
background data. If you do not call this block, HealthKit continues to
attempt to launch your app using a backoff algorithm. If your app
fails to respond three times, HealthKit assumes that your app cannot
receive data, and stops sending you background updates.
From looking at other posts it seems like there's a lot of confusion revolving around this handler. Below are some questions that I have about it:
When should the handler be called? If called too late, then HK might think that the app never received the query update causing you to hit the background update 3-strikes back-off algorithm. The documentation states that it should be called after handling other queries. Depending on how long it would take to run those queries, it sounds like you could get dangerously close to hitting the background update strikes.
Why is this needed? Shouldn't the system know that the app has been launched and has received the background update? When using CoreBluetooth in the background it just wakes your app up in the background for 10 seconds. No need to call any handler or deal with the background update 3-strikes.
If you hit the background update 3-strikes and HK stops sending updates is that permanent? Does HK ever start sending the background updates again? What if there's a bug that prevented the handler to be called and now you've fixed it. Is the app stuck never receiving the updates? Or will it reset when the app is re-launched or updated?
Does HK keep your app running in the background until the handler is called? Is that part of its purpose or just a side effect? If it's part of its purpose how long can we run before needing to stop (and hit the first background update strike)?
When should the handler be called?
Call it after you are done your job. Your code should not do complex operations. The app is in the background and the user does not see what's changed. You can just set a "flag" that data is updated and do complex operations after the user launched the app. If your decision about either notifies the user or not based on complex operations, then try to refactor code so that all necessary data is pre-calculated (e.g. in UserDefaults) and extra data is simply fetched with that data. So, 1-2 seconds is enough for your calculation.
Why is this needed?
All such handlers have completion closures. They are needed for iOS to know if your app works fine. If your app will eat too much CPU time, then iOS could become slow. Hence, Apple wants to be sure that iOS works fine despite bad apps.
If you hit the background update 3-strikes and HK stops sending updates is that permanent?
No.
Does HK ever start sending the background updates again?
Yes. But it depends on many factors. It may try to call your app again in 1-2 days. If nothing changes it will call it rarely.
Does HK keep your app running in the background until the handler is called?
This is unknown. It depends on many factors. Probably if iPhone is charging it will allow running your app longer just to estimate if the completion handle is called or not. If your iPhone is not charging and closed to 0% battery, then more likely iOS will kill your app. So, you should not do any job after you called the completion handler. And try to keep it simple.
Recommendations
You should process new data as quickly as possible. If you need to fetch a lot of data, then try to optimize this and pre-calculate it when the app is in foreground, then save somewhere (UserDefault), and use new data with cached data to make a decision (e.g. notify user about something; I believe you need background updates exactly for that).
1-2 seconds or less is a good time for background updates.

Saving in Background Thread not getting finished

I have an instance of AVAudioRecorder and I have noticed that when the user closes the app too fast with a larger recording the file does not get saved properly.
This even happens when I call [recorderObject stop] in the main thread and the file gets saved locally.
I have also tried moving the file after the recording has stopped (in the (void)audioRecorderDidFinishRecording:successfully: method). But I have noticed that when I do the move with NSFileManager in a background thread with high priority, it too doesn't always finish.
Is there a way for me to insure that the files get saved, even if the user exits the app shortly after finishing a longer recording?
Thanks
Review Apple's documentation for executing tasks in the background.
Apps moving to the background are expected to put themselves into a
quiescent state as quickly as possible so that they can be suspended
by the system. If your app is in the middle of a task and needs a
little extra time to complete that task, it can call the
beginBackgroundTaskWithName:expirationHandler: or
beginBackgroundTaskWithExpirationHandler: method of the UIApplication
object to request some additional execution time. Calling either of
these methods delays the suspension of your app temporarily, giving it
a little extra time to finish its work. Upon completion of that work,
your app must call the endBackgroundTask: method to let the system
know that it is finished and can be suspended.

write to database when ios app in background state

When iPhone app is in background state or when app is minimized, I want to monitor the duration of time the app is in background and on every regular interval like every 24hrs need to get updates from web server and write the modifications in my local database.
This monitor cycle will repeat as long as app is in background. Is this kind of task is possible in iPhone applications ? Could any body help me how can I perform these tasks when app is in background state ?
beginBackgroundTaskWithExpirationHandler: is the API to make the app in background for long tasks but how long will this support.
Background tasks are killed after 10 minutes time, so to answer your question: No, it's not without faking some kind of long term event handling through a significant location's update, and even then, you have no control over when exactly the events are sent. On the other hand, using APNS to alert the user to a change has the possibility of being ignored, but comes with regularity.

iOS background uploading of images

I have made an application which uploads a bunch of photos to a web server. It does so by repeated html calls, using multiple AFNetworking's AFHTPRequestOperation inside an operation queue. Right now, of the user exits the application, the queue stops. However, I want to continue the uploading queue until it's done, and then let the application go to sleep like it normally does.
I know that iOS provides a background expiration handler using "beginBackgroundTaskWithExpirationHandler" . I also know that AFURLConnectionOperation which is superclass of every HTTP operation class in AFNetworking can use that using
- (void)setShouldExecuteAsBackgroundTaskWithExpirationHandler:(void (^)(void))handler
But is there any way of making this work with an operation queue? Will setting the expiration handler of each operation do the job properly if I want to upload, let's say 10 photos?
I would appreciate any comments on background tasks with AFNetworking, or if anyone has experienced the same problem as me.
When an app goes to background, the OS will decide whether or not to completely stop your app or give it some time to complete what it's doing. In case it wants your app to stop, the expiration handler is called. If that's happening you should suspend all your tasks as fast as possible and prepare for a complete kill of the app, because that is what will happen a very short time after (5 seconds max). Take a look here.

Resources