[iOS / UIKit] AppDelegate와 SceneDelegate - 앱의 생명주기

UIKit으로 iOS앱 개발을 할 때 중요하게 여겨지는 것이 앱의 생명주기VC의 생명주기이다.

앱이 실행중인지, 혹은 종료되었는지, 아니면 백그라운드에서 실행중인지에 따라 개발자가 처리해주어야 하는 동작이 달라질 수 있기 때문이다.

 

이 글에서는 먼저 앱의 생명주기를 담당하는 AppDelegate와 SceneDelegate에 대해 살펴보겠다.

 


앱의 생명주기가 뭐지?

먼저, 앱의 생명주기란 앱이 켜지거나 꺼질때, 혹은 앱이 백그라운드에 있을때 등의 앱의 상태를 나타내는 말이다.

개발자는 이러한 앱의 상태에 따라 특정한 처리를 해줄 수 있다.

 

크게 앱의 생명주기라고 말했지만 사실 Process LifecylceUI LifeCycle로 구분되어있다.

Process Lifecycle이 앱의 실행과 종료일때를 다루고, UI Lifecycle은 앱이 백그라운드 상태인지를 다룬다.

예전에는 이 두가지 생명주기를 AppDelegate가 모두 담당하고 있었는데, 현재는 UI Lifecycle의 경우 SceneDelegate에서 담당하게 됐다.

 

각 생명주기의 상태는 다음과 같이 정리해볼 수 있다.

  • Not Running: 아이폰에서 어떤 앱도 실행되지 않은 상태
    • Forground: 앱이 화면에 보이는 상태
      • Active: 앱이 실행중인 상태
      • Inactive: 전화, 알람등으로 인해 어떤 신호도 못받는 상태
    • Background: 앱이 화면에 보이지 않지만 코드를 실행하고 있는 상태
  • Suspend: 앱이 곧 종료될 상태(앱 선택기에서 앱을 밀어서 종료할 때)

※ 참고로 앱 선택기의 모든 앱이 Background인것은 아니다, 시간이 지나면 기기가 앱을 알아서 종료시킴

 


SceneDelegate가 등장한 이유

iOS13 이전까지는 위에서 말한 Process Lifecycle과 UI Lifcycle 모두 App Delegate에서 관리해주었다.

그러나, iOS 13에서 iPadOS의 멀티윈도우 기능이 등장함에 따라 UI Lifcycle이 다양해지면서, 이를 관리하기가 복잡해졌다.

즉, 아래 그림과 같은 상황에서 앱 프로세스는 하나인데 여러 Scene을 동시에 사용할 수 있게 되는 사례가 생긴 것이다.

iPadOS의 멀티윈도우 기능 - 같은 앱을 동시에 두 개 띄울 수 있게 되었다.

 

 

그래서 iOS13부터 UI Lifcycle을 Scene Delegate라는 별도의 객체에서 관리해주게 되었다.

SceneDelegate에서 Scene이 새롭게 생성되고 종료되는 트리거를 AppDelegate에게 알려줌으로써, AppDelegate가 앱의 생성과 종료 시점을 통제하는 식으로 동작하게 된다.


그래서 어떻게 쓰는데?

앱의 생명주기를 통해 개발자는 여러 상황에 대응할 수 있게 되었다.

 

예쁘게 만들어놓은 런치스크린이 앱이 너무 빠르게 실행돼서 보이지 않는 경우가 있을 수 있다. 그럴땐 앱이 구동되기 전의 시점에 동작을 지정함으로써 관리할 수 있다.

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        
     sleep(2)
        
     return true
}

여기서  `didFinishLaunchingWithOptions`는 앱이 본격적으로 구동되기 전의 일을 한다고 생각하면 되는데, `sleep(2)`라는 동작을 하게 함으로써, 앱이 구동되기 전에 런치스크린을 2초동안 보여주도록 할 수 있다.

※ 물론 이런 코드는 많이 쓰지 않는다, 예시를 위한 코드!

 

 

그렇다면 UI Lifecycle은 어떻게 활용할 수 있을까?

유튜브 프리미엄을 결제하지 않은 사람은, 영상을 보다가 백그라운드로 나갔을 때 영상이 중지될 것이다. 반면 프리미엄을 구독중인 사람들은 계속 영상이 재생될 것이다.

그리고 다시 포그라운드로 돌아왔을 때, 프리미엄을 구독하지 않은 사람들에게 구독 유도 알림창을 띄우는 동작도 할 수 있을 것이다.

이러한 동작들을 하는 시점을 바로 UI Lifecycle을 통해 다룰 수 있다.

func applicationDidEnterBackground(_ application: UIApplication) {
        // 유튜브 프리미엄 결제하지 않았을 때: 영상 중지
        // 금융앱 등에서 보안을 위한 화면을 띄움
    }
    
    func applicationWillEnterForeground(_ application: UIApplication) {
        // 유튜브 프리엄 결제하지 않았을 때: 프리미엄 결제 유도 팝업 띄움
        // 금융앱 등에서 faceId를 다시 함
    }
// ...

위의 함수들은 이름에서도 알 수 있듯이, 앱이 백그라운드 상태로 들어갔을 때, 포그라운드 상태로 들어갔을때의 상황을 다룬다.

주석에 쓰여있는것 처럼 금융앱의 경우도 생각해볼만한 사례인 것 같다.

 

다시 한 번 언급하자면, 첫 번째 사례에서 `didFinishLaunchingWithOptions` 등의 process Lifecycle 관련 함수는 AppDelegate에서, 두 번째 사례에서의 `applicationDidEnterBackground`, `applicationWillEnterForeground`등의 UI Lifecycle 관련 함수는 SceneDelegate에서 처리한다.

 


이렇게 iOS의 앱 생명주기에 대해 살펴볼 수 있었다.

이와 더불어 중요한 개념인 VC의 생명주기에 대해선 차후 다른 글에서 다뤄보도록 하겠다.

 

※ 참고자료

https://developer.apple.com/documentation/uikit/uiapplicationdelegate

 

UIApplicationDelegate | Apple Developer Documentation

A set of methods to manage shared behaviors for your app.

developer.apple.com

https://developer.apple.com/documentation/uikit/uiscenedelegate

 

UISceneDelegate | Apple Developer Documentation

The core methods you use to respond to life-cycle events occurring within a scene.

developer.apple.com