All You Need to Know About the iOS App Lifecycle (Part 1)

Knowing about the states that iOS apps go through as they run is key to building solid apps. You'll find that it's an often asked interview question, so now is a good time to listen up. We'll look at the essentials of the iOS app lifecycle, so you can prepare apps for any state changes.

Written by 

An iOS app has several different states it can be in between launch time and termination. Let's get an overview of the different states by looking at the figure below:

From this, we see that the app can either exist in the foreground, background or not be running.

  • Foreground (green section): the app is the user's focus of attention and can receive UI events.
  • Background (blue section): the app is not visible but is still running code for a limited time.
  • Not running (no section): the app is not running any code at all.

Besides these, the app transitions between individual states (transitions shown with arrows in the figure). We can hook into these transitions in our code and execute appropriate state handling as transitions happen. Most notably in our app's AppDelegate. We'll look much more into handling of state changes in the next post. For now, our focus is to understand each state change.

Not running to inactive

Let's start by looking at our first state change, going from "not running" to "inactive". During "not running", no process is running our app. It's not getting any CPU cycles. An obvious way of getting out of this state is by launching the app. This takes our app from "not running" and to the foreground in the "inactive" state. The "inactive" state is when the app is running but not receiving UI events. The app is still getting started up. The app resides in this state briefly, before it's fully launched and enters the "active" state. Here, the app is ready to receive events.

As previously mentioned, handling of state changes can be done in the AppDelegate. During this state change, the following AppDelegate method gets called:

func application(UIApplication, will/didFinishLaunchingWithOptions: [UIApplication.LaunchOptionsKey:Any]?)

As we see from this method, a dictionary is passed in. This lets you know why your app was launched. A reason for this could be that you pressed the app icon. But there are tons of other ways an app can get launched. For instance, CoreLocation provides functionality for launching the app if the user walks within certain set of coordinates.

If you use the NotificationCenter to listen for state change you would add an observer of the following notification:

UIApplicationDidFinishLaunching

If you're unfamiliar with NotificationCenter. Don't worry, I'll get to this in the next post.

Active to inactive

The next transition we'll look at is going from "active" to "inactive". This could happen if we implement pausing in our app and show a pause menu. Another reason might be that a phone call comes in. Or simple when our app is on the way to be thrown to the background. In any case, we should handle it by performing a pause. For instance, in a game we would display a pause menu.

The method we would implement in the AppDelegate is this:

func applicationWillResignActive(UIApplication)

If you'd rather listen for state change in your view controller, here's the notification:

UIApplicationWillResignActive

Inactive to active

The transition from "inactive" to "active" is relevant, when you need to unpause your app. This is where you'd close the pause menu and reactivate things. It will also be triggered whenever you hang up a phone call that initially paused your app. Let's look at the AppDelegate method that gets called:

func applicationDidBecomeActive(UIApplication)

And using NotificationCenter you can observe the following notification:

UIApplicationDidBecomeActive

Foreground to background

When someone exits your app by pressing the home button, you app will be moved to the background. Now it time to be respond to this state change quickly, as you only get to run for about 30 seconds at this point. This means that you should hurry and clean up, as you could get suspended and afterwards killed at any time. It is possible to request more time, but don't abuse this (or the system will kill you instead).

Looking at the AppDelegate, the method you'd implement is:

func applicationDidEnterBackground(UIApplication)

Or simply observe the following notification:

UIApplicationDidEnterBackground

Background to foreground

Phew, you app didn't get killed as the user made your app active again. Now, let's bring things back up and undo what whatever we did when entering the background. You know the drill by now. The AppDelegate method to look at is:

func applicationWillEnterForeground(UIApplication)

And you can observe this notification:

UIApplicationWillEnterForeground

Background to suspended

After a little while of being backgrounded, your app gets suspended. This means no code running at all. Your app's process still exists but it's not getting CPU cycles. When suspended your app can get killed at any point in time. So if you got any last words, you should implement the following AppDelegate method:

func applicationWillTerminate(UIApplication)

Or simply listen for this notification:

UIApplicationWillTerminate

Wrapping up

This was part 1 of 2 in this short series of posts about the iOS app lifecycle. We touched upon the entire iOS app lifecycle from launch to termination. We looked at all the state changes that we can handle in our code, through our AppDelegate or by listening for the given notification. In the next part, we'll take a closer look at how we use code to react to state changes.

Thanks for reading. Remember to leave a comment and share with your fellow developers.

Leave a Comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.