iPhone App transiting from active to inactive state - ios

Assume that I am build an iPhone application which accepts user name and password in one of the screens. While I am entering my username, I get an high priority event like a phone call.
My app will transit from being active to an inactive state at this point.
My question here is: What are the steps that I need to do in my app so that I can save the current application state (and entered info) so that I can restore the same when my app becomes active later on?
This question was asked in one of iOS interviews.
My answer was that handle the active to inactive state transition in the applicationWillResignActive delegate method to save the partially entered user info details and restore it in applicationDidBecomeActive method. The App UI state, we don't have to handle as the OS will take care of it.
It looked like the interviewer was not convinced with my answer. He kept asking me as to how would you handle (steps that you would take in your app) the transition from an active state to inactive state and then to active state in your app so that app state is restored/intact?

Your answer is correct, the interviewer was probably looking for you to name each of these methods and you most likely only named the two you stated. There are a few other delegate methods for certain App UI states, such as applicationDidEnterBackground and applicationWillEnterForeground
If you read the default description of these methods in the comments you will get a better understanding of what each is used for. For example, applicationWillResignActive specifically refers to incoming phone calls or SMS messages:
// 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.
And applicationDidEnterBackground is for saving user data when a user closes your app:
// 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.
Check out your AppDelegate.m file of a new project and the comments really are very, very useful for understanding exactly which ones will handle what states and when you should use each.
Also, be sure to read up on Apple's documentation on handling application states: The App Life Cycle

Apple has already provided decent documentation on your question:
link.
And for interruptions:
link for apple developer site on handling interruptions

I think you are talking much more about restore state.
First of all, implement App delegate protocol:
func application(application: UIApplication, shouldRestoreApplicationState coder: NSCoder) -> Bool {
return true
}
func application(application: UIApplication, shouldSaveApplicationState coder: NSCoder) -> Bool {
return true
}
Then in your ViewController, implement UIStateRestoring protocol. Here you should notice that if you want archive your own complicated object, don't forget to implement NSCoder.
Please go deep into "State Restoration".
Besides, when your app go to background, you need to do some work such as stop timer, pause ongoing task.
When go to foreground, you need to do something like start the paused task, and prepare to refresh page.

Related

How to detect when a user terminates an app - Swift

Not sure why this is so challenging for me, but how can I detect when the user terminates the app? Because from what I'm seeing, Apple provides a lot of functions that might or might not be called when an app closes.
func applicationWillTerminate(_ application: UIApplication): Called when (most) apps are terminated, but not for apps that support background execution.
func sceneDidEnterBackground(_ scene: UIScene): Called when the scene enters the background, but can't differentiate between the app entering the background versus terminating completely.
func sceneDidDisconnect(_ scene: UIScene): I confirmed this is called if the user directly terminates the app, but if the app is put in the background and then terminated, it isn't called..
// EDIT: So I realized the above method (sceneDidDisconnect) is indeed the function I was looking for. I previously thought it wasn't being called in the latter case described above, but in actuality, it was. See the (soon to be) accepted answer as well.
Is there a function that's called every time a user terminates an app???
func sceneDidDisconnect(_ scene: UIScene) ended up being the function I was looking for. It's called whenever the user manually "terminates" the app...
...although as #dfd commented
"In iOS, typically it's the OS that terminates an app for a variety of reasons (not necessarily the user)."

Is there any callback methods to be called When the user closes the app from the Task Manager when app is going in the background state already?

Is there any callback methods to be called When the user closes the app from the Task Manager? Because i have to maintain the status i.e Online or Offline while killing the app from the task manger user should become offline.
No, there is no such method or function or method to handle this scenario.
func applicationWillTerminate(application: UIApplication){}
// This method will be called when system kills your app after suspending it for whatever reason.
There is no method to detect killing application by multitasking and swipe the app Up to kill(from task manager).
Though you can handle this scenario in
func applicationDidEnterBackground(application: UIApplication) {}
Previous answers contain needed information. The application has delegate #protocol methods that handle application appearance, focus, entereing background state or termination.
If your question is how to handle this events in the context of data transfer and sending some status outside - register NSNotification observer and postNotification from the delegate protocol handler. Notifications are being sent before any other actions and allow the app to inform remote resource that it will be closed or loses focus.
In Ruby
at_exit do
# Do whatever you want before exit
end
Or if you want to do something before a specific signal that causes your program to exit, then
trap :INT do
# Will be triggered when `SIGINT` is trapped
end
You can replace :INT with other signals you want to trap.

iOS - How to guarantee that applicationWillTerminate will be executed

Is there A way to guarantee that the applicationWillTerminate method in the AppDelegate delegate will be hit? Something like a key in the info.plist file, etc..?
My goal: I'm working in a beacon app, the piece of code is in this article. My problem is that the message from the didEnterRegion keeps poping even when i'm beside the beacon. To solve that I'm setting a flag to control the message. My code below:
if(!UserDefaults.standard.bool(forKey: Constants.EnterZoneMsgShowName)){
let notification = UILocalNotification()
notification.alertBody = "Hi, you are about to arrive at CIDMA's office. Please open de demo app and turn on the bluetooth on your device to enrich your experience. "
UIApplication.shared.presentLocalNotificationNow(notification)
UserDefaults.standard.set(true, forKey: Constants.EnterZoneMsgShowName)
}
I want to set this flag to false when I close the app. I tried to put it at the applicationWillTerminate but this method is not hit every time.
I would like to know how to guarantee that this code will be hit or if there is a better place to put the code: UserDefaults.standard.set(false, forKey: Constants.EnterZoneMsgShowName)
applicationWillTerminate(_:) - Tells the delegate when the app is about
to terminate.
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.
What you want to call is applicationDidEnterBackground if your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.

Call order of performActionForShortcutItem vs applicationWillEnterForeground

So, i have an app that has server state, and i refresh it by a timeout value and checking that timeout in applicationWillEnterForeground, reloading if timeout has expired.
This has worked well up until now.
I now want to implement new force touch shortcut action that performs a server operation. However, i don’t want the status-fetch operation to happen at the same time as the shortcut action. This is not a problem when the app is launched through a shortcut, but when transitioning from inactive -> active, i could end up starting one server operation in the applicationWillEnterForeground, and another in performActionForShortcutItem, which is not optimal.
What i'm after is to only potentially refresh my state if the app is not (re)launched as a result of a force touch press.
I thought i would solve this by a bool, “isHandlingShortcut” that i set in performActionForShortcutItem and then check in applicationWillEnterForeground, and in that case skip my refresh - but turns out it doesn’t work since applicationWillEnterForeground is called first!
Is there any way i can find out that i’ve (re)launched the app via a shortcut in applicationWillEnterForeground?
EDIT: perhaps i could move my "refresh"-logic to applicationDidBecomeActive? That one is called after performActionForShortcutItem.
According to the documentation:
[...] check, on launch, whether your app is being launched via a quick
action. Perform this check in your
application:willFinishLaunchingWithOptions: or
application:didFinishLaunchingWithOptions: method by checking for the
UIApplicationLaunchOptionsShortcutItemKey launch option key. The
UIApplicationShortcutItem object is available as the value of the
launch option key.
https://developer.apple.com/documentation/uikit/uiapplicationdelegate/1622935-application
What I'm doing is checking the shortcut that comes in didFinishLaunchingWithOptions so later in performActionForShortcutItem I know whether the app was launched due to the shortcut or the app was already launched.
In didFinishLaunchingWithOptions (executed if shourtcut launches the app):
self.launchShortcutItem = launchOptions[UIApplicationLaunchOptionsShortcutItemKey];
And later in performActionForShortcutItem:
if (self.launchShortcutItem) {
// app launched due to shortcut
} else {
// app was already launched
}

SWIFT: how to run a function even when user kills the app

I am using swift 2 and Xcode7 for iOS9. I want to know if I can maintain a function (that checks for something to delete) running "forever" even if the user kills the app?
I am deleting contacts from the contact list according to some rules and time. It is running ok, but just with the app opened or in second plan. I want to make this app capable to delete those contacts even when the user kills it.
You can use background thread when user opens the app. But if the app will be terminated, there is no option to run functions.
Look for the app lifecycle here and redesign your architecture: https://developer.apple.com/library/ios/documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/TheAppLifeCycle/TheAppLifeCycle.html
If the user kills the app it is no longer running, therefore your code is no longer running. There is no such state that your code/app can be in where this is possible.
By "kill", I don't mean "background". Backgrounding an app is different. Check Apple's docs on the different app states (see m.albin's answer) as well as various strategies for handling those app states.
func applicationWillTerminate(_ application: UIApplication) {
// Called when the user discards a scene session.
// If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions.
// Use this method to release any resources that were specific to the discarded scenes, as they will not return.
print("Application Will Terminate")
}

Resources