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.
Related
I am trying to understand Apple's doc for Background Execution:
Once configured, your NSURLSession object seamlessly hands off upload
and download tasks to the system at appropriate times. If tasks finish
while your app is still running (either in the foreground or the
background), the session object notifies its delegate in the usual
way. If tasks have not yet finished and the system terminates your
app, the system automatically continues managing the tasks in the
background. If the user terminates your app, the system cancels any
pending tasks.
When all of the tasks associated with a background session are
complete, the system relaunches a terminated app (assuming that the
sessionSendsLaunchEvents property was set to YES and that the user did
not force quit the app) and calls the app delegate’s
application:handleEventsForBackgroundURLSession:completionHandler:
method. (The system may also relaunch the app to handle authentication
challenges or other task-related events that require your app’s
attention.) In your implementation of that delegate method, use the
provided identifier to create a new NSURLSessionConfiguration and
NSURLSession object with the same configuration as before. The system
reconnects your new session object to the previous tasks and reports
their status to the session object’s delegate.
If I use NSURLSession, so when app goes background when uploading process is still on going, the process won't be killed or died as long as the application isn't terminated by user (I assume this is by killing my app from app list) ?
Read the text carefully. As all good documentation, it says very clearly what it means, and you just need to read it carefully.
You didn't read it carefully.
There are three cases: Your app is still running when a task finishes, your app has been shut down by the system when the last task finishes, or the user has closed down the app before the last task finishes. No, it doesn't say anywhere that the app is kept alive. And the documentation says clearly what happens in each case.
iOS kills apps that are in the background and makes it look to the user as if they are still running.
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.
I'm working on an iOS app, uploading videos from the Camera Roll, using NSURLSession with a background configuration. The user can queue up multiple videos for upload (the queue is executed serially).
A single upload consists of:
Getting an AVURLAsset reference to the PHAsset using PHImageManager's requestAVAssetForVideo method.
Exporting the resource to a temp directory (because you cannot upload straight from the AVURLAsset's URL).
Uploading the resource using an NSURLSessionUploadTask
I can queue up multiple videos and the process works well in the foreground. They complete one after another.
But if I queue up several videos and then background the app. As soon as execution reaches the exportAsynchronouslyWithCompletionHandler: stage it stalls until I foreground the app again. (I know this because I'm posting debug statements in local notifications, visible on the lock screen).
Is it possible to use exportAsynchronouslyWithCompletionHandler: when the app is backgrounded?
Edit 1
I've tested this while connected to the debugger and while not, the app never executes the copy command. But does so only when the app is foregrounded again.
Edit 2
I posted a similar question about whether using NSFileManager's copyItemAtURL:toURL:error: is a viable alternative (but I'm seeing the same behavior so don't think it is).
In general, if you need just a little time (up to a few minutes) to finish up some tasks even after the user leaves the app, you just request this from the OS. See the Executing Finite Length Tasks section in the Background Execution Chapter. So, begin the background task when you call exportAsynchronouslyWithCompletionHandler, and end it in the completion handler for that method.
If you are also using a background NSURLSession. In that case, if the app is not in foreground when the tasks finish, it calls the app delegate's handleEventsForBackgroundURLSession method, which passes a completionHandler block. One must:
Save the completionHandler provided to handleEventsForBackgroundURLSession;
Instantiate the NSURLSession with the same background identifier as the original background session;
Let the session call the appropriate delegate methods for the completion of the tasks; and
The session will call URLSessionDidFinishEventsForBackgroundURLSession when they're all done, at which point you'd generally call the completionHandler we originally received in the app delegate.
In your case, you will want to defer the call to the saved completionHandler until after all of the asynchronous exportAsynchronouslyWithCompletionHandler handlers are done, too. There are bunch of ways you could do that (e.g. dispatch groups, etc.), but hopefully that illustrates the moving parts involved in this process.
Every time my app loads it calls a web service to check if an update is available to download for the app. If there is it downloads it.
I'm using Grand Central Dispatch to synchronously download the updates in a different thread so I can show a loading icon on my main thread. I need to synchronously download because the app needs the updates before it continues.
However the problem occurs if the download takes a while and the screen goes to sleep, effectively calling applicationDidEnterBackground. When the user turns the screen back on and the app resumes I get the following error:
EXE_BAD_INSTRUCTION (code=EXC_1386_INVOP, subcode=0x0)
What is the best way around this? Trying to pause the download and resume again when the app resumes or to create a background task and continue downloading? I'm not sure which is the best method.
I think the safest answer would be that, unless your app otherwise has background privileges (audio, gps, external device, etc), yes, you should pause/stop any network downloads when -applicationDidEnterBackground is called and resume when your app comes back.
Is applicationDidEnterBackground ALWAYS called before applicationWillTerminate in an iOS app? I know that applicationWillTerminate is not always called (multitasking) - but when it is called, is applicationDidEnterBackground ALWAYS called first? I don't want to duplicate code unnecessarily by including it in applicationWillTerminate if it is already included in applicationDidEnterBackground, for an app that supports multitasking.
in ios 4.0 and later applicationDidEnterBackground is called instead of applicationWillTerminate so you don't have to call both of them. Here is the portion of the Apple docs:
Discussion
In iOS 4.0 and later, this method is called instead of the
applicationWillTerminate: method when the user quits an application
that supports background execution. You should use this method to
release shared resources, save user data, invalidate timers, and store
enough application state information to restore your application to
its current state in case it is terminated later. You should also
disable updates to your application’s user interface and avoid using
some types of shared system resources (such as the user’s contacts
database). It is also imperative that you avoid using OpenGL ES in the
background.
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 application 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.
The application also posts a
UIApplicationDidEnterBackgroundNotification notification around the
same time it calls this method to give interested objects a chance to
respond to the transition.
For more information about how to transition gracefully to the
background, and for information about how to start background tasks at
quit time, see iOS App Programming Guide.
Hope this helps clear the issue for you man.
Adrian
Here is the link to the technical note that is available on developer section. It is dealing with networking and multitasking. The actual method used in this doc deals with only applicationDidEnterBackground and since iOS 5 they have a system called watchdog which terminates the app if the network is unresponsive automatically. Hence there is no need to actually call applicationWillTerminate and try to execute codes to allow your app to finish its task before the app is terminated. The app will enter the background and will continue its task until the last task is completed. I hope that makes sense, but here is the link. Please read the watchdog section.
https://developer.apple.com/library/ios/#technotes/tn2277/_index.html#//apple_ref/doc/uid/DTS40010841
Hope this helps. :)