If you're creating and managing timers via GCD with dispatch_source_create, dispatch_resume and dispatch_suspend, I know that you have to always make sure that for every dispatch_suspend, there has to be a matching dispatch_resume.
So when an application enters background mode, you would call dispatch_suspend and upon receiving applicationDidBecomeActive, call dispatch_resume on the timer sources that were previously suspended.
What about the dispatch_resume when an application was force killed (via bringing up the list of apps running in background)? Do you have to worry about it all? I presume that when the app is restarted, application:didFinishLaunchingWithOptions is invoked as if the app is starting cleanly.. Is this assumption correct?
Yes. If your backgrounded app gets killed by the user via the multitasking tray, or killed by the system to free up memory, launching the app again will be just the same as launching it for the first time.
Related
I want to count costumer time(like this 00:20:04). But background app can work only 3 min.
I have timer for it, and I can count with NSDate how many seconds app be close. But don't know how call this func.
So my question is: How app can understand when app in background and stop work, and how understand when return to app?
Short answer:
Save current time when user start counting and calibrate it in applicationWillEnterForeground: , in fact you can just calibrate it in your code of setting up timer.
Long answer:
You won't receive any notification if your app is in suspend mode and then terminated.
Apps must be prepared for termination to happen at any time and should not wait to save user data or perform other critical tasks. System-initiated termination is a normal part of an app’s life cycle. The system usually terminates apps so that it can reclaim memory and make room for other apps being launched by the user, but the system may also terminate apps that are misbehaving or not responding to events in a timely manner.
Suspended apps receive no notification when they are terminated; the system kills the process and reclaims the corresponding memory. If an app is currently running in the background and not suspended, the system calls the applicationWillTerminate: of its app delegate prior to termination. The system does not call this method when the device reboots.
In addition to the system terminating your app, the user can terminate your app explicitly using the multitasking UI. User-initiated termination has the same effect as terminating a suspended app. The app’s process is killed and no notification is sent to the app.
However you can use these method of AppDelegate to get notified when your app is launched, entering background or foreground:
application:willFinishLaunchingWithOptions:—This method is your app’s first chance to execute code at launch time.
application:didFinishLaunchingWithOptions:—This method allows you to perform any final initialization before your app is displayed to the user.
applicationDidBecomeActive:—Lets your app know that it is about to become the foreground app. Use this method for any last minute preparation.
applicationWillResignActive:—Lets you know that your app is transitioning away from being the foreground app. Use this method to put your app into a quiescent state.
applicationDidEnterBackground:—Lets you know that your app is now running in the background and may be suspended at any time.
applicationWillEnterForeground:—Lets you know that your app is moving out of the background and back into the foreground, but that it is not yet active.
applicationWillTerminate:—Lets you know that your app is being terminated. This method is not called if your app is suspended.
read iOS app life cycle and UIApplicationDelegate Protocol Reference for more detail.
While the device is powered on, is it possible for iOS to automatically terminate my app (calling applicationWillTerminate:) while it's in the background?
I'm also curious what happens in two other cases, three in total:
Device is powered on
Device is powered off
Device loses battery
I'm asking because I want to know how often applicationWillTerminate: is likely to get called. I want to know this because that's where I'm registering for remote notifications. And if there's a failure sending the device token to the server, I want to know how likely it is that that method will get called again (i.e., retry sending the device token to the server).
If your application supports multitasking (the default for anything linked against iOS 4.0+), this method will almost never be called. The documentation says it may be called in cases where the application is running in the background and the system wants to terminate. However, in my experience, I've only ever seen this actually called when running a music app that's actively playing music in the background and the system is jettisoning everything. In cases where I have background tasks running (not music, but short-term background tasks), I've seen the app terminated without this method being called.
I wouldn't ever rely on this being called and try and do all the clean-up you need to do in your delegate methods for transitioning into the background and your background task completion blocks (which do get executed for at least a few seconds before the app gets jettisoned).
Not only can iOS terminate your app automatically, but the user can kill it manually. In fact, the only time the user can kill your app is when it's in the background. Furthermore, when your app is "in the background" it's more likely to be suspended than actually running, so don't count on doing a lot of processing when you're not the foreground app.
As for how likely it is that you'll get -applicationWillTerminate:, that'll depend on the user and how they're using their device. You should handle it appropriately when you get it, and go about your business otherwise.
When memory is running low, iOS can shut down your app, calling applicationWillTerminate.
The docs say this about the method:
... However, this method may be called in situations where the application is running in the background (not suspended) and the system needs to terminate it for some reason.
Check out iOS Developer Library : iOS App Programming Guide : App Termination.
So here is the issue I am facing. Certain portions of the application I am building open some c network sockets that allow connections to various servers/services. However, if the application goes to sleep, these socket connections are lost, and error out when trying to reload them. So what I want to do is basically notify the user when the app launches again, that the application needs to be restarted. The main question is, can I present them with a button that will kill the app by using exit(0) without my app getting rejected?
Apple says that the user should be in control of when the app is killed, and in this case I see that they are, but I am not sure of Apple's opinion on this. Has anyone else used this? Have you been rejected for this? Thanks in advance for any advice!
EDIT:
Thank you everyone for your advice. I am trying to take everything into consideration, but because the app needs to be submitted ASAP, I just need to know, if we can not get another solution, if the above proposed solution, will get rejected or not.
Your application delegate receives notifications when significant events affect the life of the application. Rather than ask your user to recreate a session, you should attempt to discontinue network operations and then resume them at the appropriate times in the application's lifecycle automatically.
You can gracefully kill network sockets (amongst other things) in any number of places as the application prepares to exit or enter the background via callbacks in your application delegate:
applicationWillResignActive:
applicationWillEnterBackground:
applicationWillTerminate:
Potentially reconstruct sockets in:
applicationDidBecomeActive
applicationWillEnterForeground
Have you tried not allowing the app to run in the background? Then it will be killed whenever the user exits to the home screen. This might be a bit aggressive, but would solve the problem. From Apple's opting out of background execution:
"If you do not want your application to remain in the background when
it is quit, you can explicitly opt out of the background execution
model by adding the UIApplicationExitsOnSuspend key to your
application’s Info.plist file and setting its value to YES.
When an application opts out, it cycles between the not running,
inactive, and active states and never enters the background or
suspended states.
When the user taps the Home button to quit the application, the
applicationWillTerminate: method of the application delegate is called
and the application has approximately five seconds to clean up and
exit before it is terminated and moved back to the not running state."
See also: How to prevent my app from running in the background on the iPhone
The documentation is pretty explicit about this, "There is no API provided for gracefully terminating an iOS application." See Technical Q&A QA1561
How do I programmatically quit my iOS application?.
To be blunt, terminating an app to cleanup a socket is just like dealing with memory management by forcing an app to exit instead of calling release.
What about bringing up a modal view controller telling the user to quit the application? You could make this view controller without any dismiss button, so the user is obligated to kill the app.
I've just been reading this post on notifications being sent to apps running in the background :
Not getting didReceiveMemoryWarning when app is in the background
My question is that since an app in the background will not act on a didRecieveMemoryWarning until it enters the foreground again, what is the recommended way to free up memory in your app if it is running in the background when the memory notification is sent - or is this not possible ?
In iOS 4.0 and later, - (void)applicationDidEnterBackground:(UIApplication *)application 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.
If your app is running in the background (because it is, for example, a Voice over IP app that is allowed to run in the background), it will receive memory warning notifications in the same way as if it were running in the foreground, and you should deal with them accordingly.
However, if your app is suspended in the background, it won't receive memory warnings or other notifications. Your job is to free as much memory as possible before your app enters the background. Once you're in the background, you have no way to do anything anymore. The OS will decide whether to kill your app or not (without notifying you again) at its discretion.
When my application is moved into the background, I'd like to be able to detect when it is about to be terminated (for memory exhaustion or other reasons). Is there a way to do this?
In particular, is there a way to execute some code before the application is terminated when in the background?
You can do this in the -[<UIApplicationDelegate> applicationWillTerminate:] method of your application delegate, like this:
- (void)applicationWillTerminate:(UIApplication *)application {
[database save]; // or whatever you want to do
}
This will be executed whenever the app is about to be terminated, unless it crashes.
Your best bet is to do whatever cleanup needs to be done in your application (saving state or user data, etc.) as your application transitions into the background. If your application is suspended, you will not have a chance to perform any last code before it is terminated by the system.
From the iOS Application Programming Guide:
If your application is running (either
in the foreground or background) at
termination time, the system calls
your application delegate’s
applicationWillTerminate: method so
that you can perform any required
cleanup. You can use this method to
save user data or application state
information that you would use to
restore your application to its
current state on a subsequent launch.
Your method implementation has
approximately 5 seconds to perform any
tasks and return. If it does not
return in time, the application is
killed and removed from memory. The
applicationWillTerminate: method is
not called if your application is
currently suspended.
Even if you develop your application
using iOS SDK 4 and later, you must
still be prepared for your application
to be killed without any notification.
The user can kill applications
explicitly using the multitasking UI.
In addition, if memory becomes
constrained, the system might remove
applications from memory to make more
room. If your application is currently
suspended, the system kills your
application and removes it from memory
without any notice. However, if your
application is currently running in
the background state (in other words,
not suspended), the system calls the
applicationWillTerminate: method of
your application delegate. Your
application cannot request additional
background execution time from this
method.
It depends.
If you mean getting notification while your application is suspended in the background, there is no way to know; the applicationWillTerminate: method is not run if you're suspended. The recommended approach is to save any required state when you get the applicationWillEnterBackground: message, so that if you get killed in the background you're ready to start up again.
If you're actually in an "executing in the background" state, (which can happen briefly after exiting the app or if the app has requested temporary background execution time,) then applicationWillTerminate: will be called just like you'd expect.