Which is the proper delegate to implement when an application is waking up from being in the background and you want it to prep it to be active?
applicationWillEnterForeground vs applicationDidBecomeActive -- What's the difference?
Which is the proper delegate to implement for when an application is going to sleep and you want to prep it to cleanup and save data?
applicationWillResignActive vs. applicationDidEnterBackground -- What's the difference?
Also, I've noticed that applicationWillResignActive gets called when an incoming SMS or call comes in but the user chooses to click Ok and continue. I don't want my app to take any action in these cases. I just want it to keep running without any intermediate cleanup since the user didn't exit the app. So, I would think it makes more sense to do cleanup work just in applicationDidEnterBackground.
I would appreciate your input on best practices to follow on choosing which delegates to implement for waking up and going to sleep as well as considering events like being interrupted by SMS/calls.
Thanks
When waking up i.e. relaunching an app (either through springboard, app switching or URL) applicationWillEnterForeground: is called. It is only executed once when the app becomes ready for use, after being put into the background, while applicationDidBecomeActive: may be called multiple times after launch. This makes applicationWillEnterForeground: ideal for setup that needs to occur just once after relaunch.
applicationWillEnterForeground: is called:
when app is relaunched
before applicationDidBecomeActive:
applicationDidBecomeActive: is called:
when app is first launched after application:didFinishLaunchingWithOptions:
after applicationWillEnterForeground: if there's no URL to handle.
after application:handleOpenURL: is called.
after applicationWillResignActive: if user ignores interruption like a phone call or SMS.
applicationWillResignActive: is called:
when there is an interruption like a phone call.
if user takes call applicationDidEnterBackground: is called.
if user ignores call applicationDidBecomeActive: is called.
when the home button is pressed or user switches apps.
docs say you should
pause ongoing tasks
disable timers
pause a game
reduce OpenGL frame rates
applicationDidEnterBackground: is called:
after applicationWillResignActive:
docs say you should:
release shared resources
save user data
invalidate timers
save app state so you can restore it if app is terminated.
disable UI updates
you have 5 seconds to do what you need to and return the method
if you don't return within ~5 seconds the app is terminated.
you can ask for more time with beginBackgroundTaskWithExpirationHandler:
The official documentation.
Managing Your App's Life Cycle is helpful to your questions. For quick concept, you can see Figures in that document.
You can also read the comment from the code generated by the XCode Wizard. Listed as follows:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// Override point for customization after application launch.
return YES;
}
- (void)applicationWillResignActive:(UIApplication *)application
{
/*
Sent when the application is about to move from active to inactive state.
This can occur for certain types of temporary interruptions (such as an
incoming phone call or SMS message) or when the user quits the application
and it begins the transition to the background state.
Use this method to pause ongoing tasks, disable timers, and throttle down
OpenGL ES frame rates. Games should use this method to pause the game.
*/
}
- (void)applicationDidEnterBackground:(UIApplication *)application
{
/*
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.
If your application supports background execution, this method is called
instead of applicationWillTerminate: when the user quits.
*/
}
- (void)applicationWillEnterForeground:(UIApplication *)application
{
/*
Called as part of the transition from the background to the active state;
here you can undo many of the changes made on entering the background.
*/
}
- (void)applicationDidBecomeActive:(UIApplication *)application
{
/*
Restart any tasks that were paused (or not yet started) while the
application was inactive. If the application was previously in the
background, optionally refresh the user interface.
*/
}
- (void)applicationWillTerminate:(UIApplication *)application
{
/*
Called when the application is about to terminate.
Save data if appropriate.
See also applicationDidEnterBackground:.
*/
}
For more detailed explanations, please refer to official document for UIApplicationDelegate
I was still a bit confused with Dano's answer so I did a little test to get the flow of events in certain scenarios for my reference, but it might be useful to you too. This is for apps that DO NOT use UIApplicationExitsOnSuspend in their info.plist. This was conducted on an iOS 8 simulator + confirmed with iOS 7 device. Please excuse Xamarin's event handler names. They are very similar.
Initial and all subsequent launches from a not-running state:
FinishedLaunching
OnActivated
Interruption (phone call, top slide-down, bottom slide-up):
Home button double-press listing inactive apps, then reselecting our app:
OnResignActivation
OnActivated
Home button double-press listing inactive apps, selecting another app, then relaunching our app:
Home button single press, then relaunch:
Lock (on/off button), then unlock:
OnResignActivation
DidEnterBackground
WillEnterForeground
OnActivated
Home button double-press, and terminate our app: (subsequent relaunch is first case)
OnResignActivation
DidEnterBackground
DidEnterBackground (iOS 7 only?)
Yes, DidEnterBackground is called twice on iOS7 device. Both times UIApplication state is Background. However, iOS 8 simulator does not. This needs testing on iOS 8 device. I will update my answer when I get my hand on it, or someone else could confirm.
applicationWillEnterForeground is called:
when app is relaunched(comes from background to foreground)
This method is not invoked when app starts for the first time i.e when applicationDidFinishLaunch is called but only when comes from background
applicationDidBecomeActive
applicationDidBecomeActive is called
when app is first launched after didFinishLaunching
after applicationWillEnterForeground if there’s no URL to handle.
after application:handleOpenURL: is called.
after applicationWillResignActive if user ignores interruption like a phone call or SMS.
after disappearing of alertView anywhere from the application
applicationWillResignActive is called when system is asking for permissions. (in iOS 10). Just in case someone hit into the same trouble as me...
In iOS 8+ there is a subtle but important difference for taking phone call.
In iOS 7 if user takes phone call both applicationWillResignActive: and applicationDidEnterBackground: are called. But in iOS 8+ only applicationWillResignActive: is called.
For iOS 13+ the following methods will be executed:
- (void)sceneWillEnterForeground:(UIScene *)scene
- (void)sceneDidBecomeActive:(UIScene *)scene
Related
I have an app that triggers local notifications every 30 minutes from the moment a certain button is tapped (both in the foreground and the background). I learned how to remove those notifications when another button is tapped or when the view controller is dismissed. This is done through:
UNUserNotificationCenter.current().removeAllPendingNotificationRequests()
It works just fine. However, if the user force-quits (shuts down manually) the app by swiping up in multitasking mode, this is when strange things start happening. By default, the terminated app doesn’t remove those pending push notifications and they keep coming even if the app is closed.
What I learned is that there are several states in the app’s lifecycle in which the app can be killed. Accordingly, there are several methods in the App Delegate that we can use to trigger the mentioned code to remove the notifications (otherwise they keep coming).
So, when we are in foreground and tap the home button (or swipe up with iPhone X) to switch to multitasking mode (choosing between active apps or deleting them), this is the time for applicationWillResignActive – we can start observing for app termination in here (maybe by means of observing applicationWillTerminate and using a certain method as a selector) and remove those notifications upon terminating (strangely enough, applicationWillTerminate doesn’t always work on its own).
However, if you switch to another app and then go back to multitasking mode, the app is in background mode this time (not inactive mode). So, there seems to be no way to trigger certain methods and observe for certain things when the app is already in background mode. I wonder if any? In this case applicationDidEnterBackground doesn’t work either. Everything ends up with “Message from debugger: Terminated due to signal 9”
So, how do you remove all pending notifications when your app is in background mode and is about to be terminated by the user? If it’s in background mode and is not going to be terminated by the user, the notifications need to stay active.
If there is a solution, please help. Or maybe there is a better way to remove pending (active) local notifications when the view controller is dismissed (it’s not the only and main view controller in the app) and when the user terminates/shuts down the app in inactive or background state? Thanks for your help.
You have few options for when the app is about to become NOT active:
func applicationWillResignActive(_ application: UIApplication) {
// Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
// Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
}
func applicationWillTerminate(_ application: UIApplication) {
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
}
func applicationDidEnterBackground(_ application: UIApplication) {
// 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.
// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
}
In your case, you should probably remove notifications in all of them, and add them again in the other functions that complement them, for example:
func applicationDidBecomeActive(_ application: UIApplication) {
// Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
}
I believe it is good practice to add and remove the notifications in the UIViewController life cycle methods, instead of in the app level life cycle
When my app is running in foreground, If user clicks on home button i want to show some alert like
Do u want to exit the app with Yes/No buttons. Is there any delegate methods called when home button is clicked…
Thank you….
There is no way to do this on iOS. I think you want a similar behavior to Android back button.
Think of iOS home button as Android home button, which doesn't let you prompt user either.
You can not stop the app to go to background, even if you show the alert message, it will go to the background anyways when you hit the home button and you won't see the alert message either.
There is no delegate method that would trigger when the app is going to the background, but there is a delegate method that will trigger when your app has totally gone to background.
Just to show you visually-
In the AppDelegate implementation file(.m), I added an alert message at the end of applicationDidEnterBackground method and put a break point just to check if it is entering that block as I expected. See the result--
You can use these methods in AppDelegate.m
- (void)applicationDidEnterBackground:(UIApplication *)application {
// 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.
// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
}
- (void)applicationWillEnterForeground:(UIApplication *)application {
// Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
}
I am asking if I can repeat a method in Xcode after home button pressed. Let's say every 30 minutes.
I have no idea to do it if it is possible.
I think your question is related to background execution by saying after home button pressed. First you need to address how to call the function in the background.
Here is what I recommend for you to follow:
First:
I recommend you to take a look at the apple official document.
https://developer.apple.com/library/ios/documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/BackgroundExecution/BackgroundExecution.html
Second:
There is a good tutorial:
http://pinkstone.co.uk/how-to-execute-a-method-on-a-background-thread-in-ios/
Third:
Here is what you are asking:
http://chrisrisner.com/31-Days-of-iOS--Day-23%E2%80%93Using-Background-Threads
Fourth:
If you want to explore the advanced material:
http://mobiforge.com/design-development/using-background-fetch-ios
use NSTimer
[NSTimer scheduledTimerWithTimeInterval:"your time"
target:self
selector:#selector(your method:)
userInfo:nil
repeats:YES];
There are Methods (like "viewDidLoad") that gets called for these cases. Here are some:
- (void)applicationWillResignActive:(UIApplication *)application
{
// Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
// Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
}
- (void)applicationDidEnterBackground:(UIApplication *)application
{
// 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.
// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
}
- (void)applicationWillTerminate:(UIApplication *)application
{
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
}
you can place the NSTimer in one of these and anything else you want to do when the home button is pressed. Hope this helps.
Source: Detect when home button is pressed iOS
Is there a way to perform some last actions when the user kills the application on iPhone?
In UIApplicationDelegate there is applicationWillTerminate: but as I understand it's not guaranteed to get called when the application terminates. Is there another way?
You can't rely on applicationWillTerminate being called. From the documentation:
For apps that do not support background execution or are linked against iOS 3.x or earlier, this method is always called when the user quits the app. For apps that support background execution, this method is generally not called when the user quits the app because the app simply moves to the background in that case. However, this method may be called in situations where the app is running in the background (not suspended) and the system needs to terminate it for some reason.
The proper place to save any state is when the app enters the background. Once that happens, there is no way to know if the app will return to the foreground or if it gets killed and then started from the beginning.
All methods concerning your app state are in your AppDelegate when you use one of the project templates.
Put the code in the applicationWillResignActive: method. It will get called if your app goes to an inactive state (terminating or no).
- (void)applicationWillResignActive:(UIApplication *)application
{
// Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
// Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
}
The "correct" place to save state is in both -applicationDidEnterBackground: and -applicationWillTerminate:. Don't worry about double-saving; generally only one of them is called (IME, -applicationWillTerminate: is not called when your app is killed in the background).
Caveat: -applicationDidEnterBackground: is not guaranteed to be called, since it is called after your app enters the background (and thus becomes eligible for killing without notice!). If the device is low on memory when your app is backgrounded, it might be killed. The best way to avoid this is to not use too much memory in the first place.
You could use
-applicationWillResignActive:, but I do not recommend this: apps become inactive quite frequently. An obvious is system dialogs (location/privacy prompts, Wi-Fi, notifications that show as alerts, alarms), TWTweetSheet, and I suspect MFMailComposeViewController, MFMessageComposeViewController, Notification Center, the app-switcher bar (e.g. to change tracks/enable orientation lock).
you can use applicationWillResignActive method in the appdelegate, or you can do the following, if you want to save stuff, but for some reason, you dont want to do it in the app delegate:
- (void) viewDidLoad/init {
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:#selector(myApplicationWillResign)
name:UIApplicationWillResignActiveNotification
object:NULL];
}
- (void) myApplicationWillResign {
NSLog(#"About to die, perform last actions");
}
I am running a synchronization process where I download files from the server into my iPad. When I am running the process in iOS6, the UI looks like this:
However, when the process is running, I close the app and return to the home screen and when I relaunch the app, it looks like this:
The screen blacks out...
At the same time, when I run this in iOS5, it works perfectly fine. But the problem is when I run it in iOS6.
At times, it runs properly returning me the red background.. at times, it returns the black screen... Totally amused by this problem...
What might be the reason?
EDIT:
- (void)applicationWillResignActive:(UIApplication *)application
{
/*
Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
*/
}
- (void)applicationDidEnterBackground:(UIApplication *)application
{
/*
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.
If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
*/
}
- (void)applicationWillEnterForeground:(UIApplication *)application
{
/*
Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
*/
}
- (void)applicationDidBecomeActive:(UIApplication *)application
{
/*
Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
*/
}
- (void)applicationWillTerminate:(UIApplication *)application
{
/*
Called when the application is about to terminate.
Save data if appropriate.
See also applicationDidEnterBackground:.
*/
}
When app goes in background OS can reduce memory usage for your app, so background view may be released. Try reloading background every time when you load the view with viewWillApperar method.