iOS Application Lifecycle

생명 주기란, 소프트웨어의 시작과 끝 사이에서 일어나는 상태나 단계의 변화입니다. iOS 앱에서는 소프트웨어의 시작은 앱을 실행시키는 것과 같고, 끝은 앱을 종료시키는 것과 같습니다. 즉, 앱의 입장에서 생명 주기란 다음과 같은 의미를 갖습니다.

“앱이 실행부터 종료될 때 까지 일어나는 상태의 변화”

이번 글에서는 iOS Application의 생명 주기(lifecycle)와 앱의 상태(App State) 및 이것이 변환되는 과정에 대해 알아보겠습니다.

App State

앱은 5가지 상태를 가질 수 있습니다.

  1. Not Running : 앱이 아직 실행되지 않은 상태입니다.
  2. In-active : 앱이 실행중이지만, 사용자와 상호작용 할 수는 없는 상태입니다.
    • 멀티태스킹 창으로 진입할 때
    • 앱 실행 중 전화, 알림 등에 의해 앱을 사용할 수 없게 될 때
  3. Active : 앱이 실행중이면서, 사용자와 상호작용하여 event를 받을 수 있는 상태입니다.
  4. Background : 앱이 화면에서 사라지고 실질적은 동작은 하지 않는 상태입니다.
    • 일반적인 경우, background 상태에 진입한 앱은 곧 바로 수 초 내에 suspended 상태로 전환됩니다.
    • Background task를 설정하는 경우, 앱은 background 상태에 머물며 낮은 우선순위로 시스템 자원을 사용하여 작업을 이어나갈 수 있습니다.
      • 음악 앱 사용 중 홈 화면으로 나가도 음악이 재생됨
      • 앱 사용 중 홈 화면으로 나가도 데이터 동기화가 유지됨
      • 시계 앱에서 타이머 설정 후 홈 화면으로 나가도 타이머가 계속 실행됨
  5. Suspended : 앱 데이터가 메모리에만 저장되어 있고, 실제로 실행되지 않는 상태입니다.
    • 시스템 메모리가 부족해지면 iOS는 가장 먼저 suspended 상태에 있는 앱 데이터를 메모리에서 해제하고 공간을 확보합니다. (앱 리프레쉬 현상)

상태 전환

앱은 실행되는 중 다른 상태로 전환될 수 있습니다. 아래 그림은 앱의 상태 변환 관계를 나타냅니다.

Active 상태와 in-active 상태가 같은 색으로 표시된 것은, 두 상태가 ‘Foreground’라는 하나의 상태로 묶일 수 있음을 의미합니다. 흔히 background 상태와 대비되는 개념으로 사용합니다.

여기서 주목할 점은, background 상태와 foreground(active) 상태 간에 전환될 때 항상 In-active 상태를 거친다는 것입니다. 즉, active 상태와 background 상태는 서로 곧바로 전환되지 않고 in-active 상태를 거쳐갑니다.

앱이 In-active 상태가 되는 경우는 세 가지입니다.

  1. 앱이 실행될 때 : Not Running -> In-active -> Active
  2. 앱이 background 상태로 진입할 때 : Active -> In-active -> Background
  3. 앱이 foreground 상태로 진입할 때 : Background -> In-active -> Active

Respond to Lifecycle

UIKit fremwork는 앱의 생명 주기 동안 앱의 상태가 변화하는 특정 시점에 event를 발생시킵니다. 우리는 특정 시점에 발생하는 event를 catch해서, 생명 주기 사이에 custom code를 끼워넣어 실행시킬 수 있습니다.

Using Notification

앱이 실행되면 UIApplication singleton 객체가 생성되는데, application 객체는 lifecycle 동안 앱의 상태가 전환되는 시점에 notification을 발생시킵니다. 앱 상태 변화와 관련된 notification은 5가지가 있습니다.

NotificationCenter에 이 notification의 observer를 등록해 두고, 특정 시점에 custom code를 실행시킵니다.

NotificationCenter.default.addObserver(
    forName: UIApplication.willResignActiveNotification,
    object: nil,
    queue: nil
) { notification in
    print("Will Resign Active")
}

NotificationCenter.default.addObserver(
    forName: UIApplication.willResignActiveNotification,
    object: nil,
    queue: nil
) { notification in
    print("Will Resign Active")
}

NotificationCenter.default.addObserver(
    forName: UIApplication.didEnterBackgroundNotification,
    object: nil,
    queue: nil
) { notification in
    print("Did Enter Background")
}

NotificationCenter.default.addObserver(
    forName: UIApplication.willEnterForegroundNotification,
    object: nil,
    queue: nil
) { notification in
    print("Will Enter Foreground")
}

NotificationCenter.default.addObserver(
    forName: UIApplication.willTerminateNotification,
    object: nil,
    queue: nil
) { notification in
    print("Will Terminate")
}

Using Delegate

UIApplicationDelegate

iOS 12까지는 UIApplicationDelegate에서 생명 주기를 관리했습니다. 아래 그림은 application이 관리하는 생명 주기를 보여줍니다.

‘Application이 생명 주기를 관리한다’는 것은, 이 delegate에 생명 주기 동안에 앱 상태가 변화할 때 호출되는 method가 정의되어 있다는 것을 의미합니다. 앱 상태와 관련된 method는 notification과 동일하게 5개가 정의되어 있습니다.

이 method들을 UIApplicationDelegate protocol을 채택하고 있는 AppDelegate에 구현하여, 특정 시점에 custom code를 실행시킵니다.

@main
class AppDelegate: UIResponder, UIApplicationDelegate {

    ...

    func applicationDidBecomeActive(_ application: UIApplication) {
        print("Did Become Active")
    }

    func applicationWillResignActive(_ application: UIApplication) {
        print("Will Resign Active")
    }
    
    func applicationDidEnterBackground(_ application: UIApplication) {
        print("Did Enter Background")
    }

    func applicationWillEnterForeground(_ application: UIApplication) {
        print("Will Enter Foreground")
    }
    
    func applicationWillTerminate(_ application: UIApplication) {
        print("Will Terminate")
    }
}

UISceneDelegate

iOS 13부터 iPad에서 화면을 두 개 이상 띄울 수 있는 multitasking 기능이 추가되면서, Scene이라는 개념이 도입되었습니다. iOS 13 이상의 OS가 설치된 기기에서 실행되는 앱은 scene을 사용한다면 UIScene에서 생명 주기 관리합니다. 아래 그림은 scene이 관리하는 생명 주기를 보여줍니다.

Scene이 관리하는 생명 주기에서 특정 시점에 호출되는 method들은 UISceneDelegate에 정의되어 있습니다.

이 method들을 UISceneDelegate protocol을 채택하고 있는 SceneDelegate에 구현하여, 특정 시점에 custom code를 실행시킵니다.

class SceneDelegate: UIResponder, UIWindowSceneDelegate {

    ...

    func sceneDidBecomeActive(_ scene: UIScene) {
        print("Did Become Active")
    }

    func sceneWillResignActive(_ scene: UIScene) {
        print("Will Resign Active")
    }

    func sceneWillEnterForeground(_ scene: UIScene) {
        print("Will Enter Foreground")
    }

    func sceneDidEnterBackground(_ scene: UIScene) {
        print("Did Enter Background")
    }
}

App-Based vs Scene-Based Lifecycle

iOS 13 이전에는 UIApplication이 생명 주기를 관리했지만(App-Based), UIScene을 사용하는 앱에서는 UIScene이 생명 주기를 관리합니다(Scene-Based). iOS 13 이상 디바이스에 설치된 앱이더라도, UIScene을 사용하지 않는다면 App-Based 생명 주기를 따라갑니다.

Scene-Based 생명 주기에서는 App-Based와 달리 ‘will terminate’ event를 전달하지 않습니다. 이것은 UISceneDelegatesceneWillTerminate(_:) 같은 method는 정의되어 있지 않는 것에서도 알 수 있는데요. 이것은 Scene-Based 생명 주기는 새로운 lifecycle이 아니라, 기존 App-Based cycle에서 UI와 관련된 lifecycle만 분리한 것이기 때문입니다.

UIScene은 하위 계층에 둘 이상의 UIWindowScene을 가질 수 있고, UIWindowScene은 둘 이상의 UIWindow를 가지고 있습니다. 그리고 앱은 UIWindow의 subview들은 화면에 보여줍니다. 즉, UIScene은 UI 요소들에 대한 생명 주기만 담당하는 것입니다.

그래서, UIScene의 생명 주기(정확히는 UI 생명 주기)를 사용하더라도 앱의 실행/종료 시점에는 UIApplicationDelegate에 정의된 method가 호출됩니다.

이렇게 UIScene이 담당하는 lifecycle을 UI Lifecycle이라고 부르고, 앱의 실행/종료 등 프로세스와 연관된 lifecycle을 Process Lifecycle이라고 부릅니다.

Scene-Based lifecycle에서 Process/UI lifecycle과 관련된 method들은 다음과 같습니다.

Summary

  1. Application Lifecycle이란, 앱의 실행부터 종료까지 발생하는 일련의 상태 변화이다.
  2. 5가지 앱 상태가 생명 주기 동안에 상호 변환된다.
    1. Not Running
    2. In-active
    3. Active
    4. Background
    5. Suspended
  3. 생명 주기 안에서 상태가 변하는 특정 시점에 custom code를 실행할 수 있다.
    1. NotifiationCenter에 observer를 등록하고 특정 시점에 발생하는 notification을 받아서 custom code를 실행한다.
    2. 생명 주기를 관리하는 객체의 delegate method를 사용한다.
      • iOS 12.0 이하 (App-Based Lifecycle)
        • Process/UI Lifecycle : UIApplicationDelegate
      • iOS 13.0 이상 (Scene-Based Lifecycle)
        • Process Lifecycle : UIApplicationDelegate
        • UI Lifecycle : UISceneDelegate