AppDelegate와 SceneDelegate

jane·2022년 5월 2일
0

iOS

목록 보기
19/32

iOS는 사용자가 앱을 직관적인 방법으로 사용할 수 있도록 디자인되었다.
따라서 iOS 개발을 하면서 우리는 사용자 경험이 물 흐르듯이 자연스럽게 이루어질 수 있도록 신경써야한다.
그러한 관점에서 앱이 처음 시작되고 종료되어 메모리에서 내려갈때까지의 생명주기인
iOS Application Life Cycle의 각 단계를 잘 이해하고 있어야 한다.

그렇다면
처음에 앱이 시작되면 가장 먼저 불리는 메서드는 무엇일까?

UIApplicationMain(::::)이다.


이 메서드는 싱글턴으로 구현된 UIApplication 객체를 생성하고, UIApplicationDelegate 프로토콜을 따르는 delegate를 정의한다.
그리고 app launch, app termination과 메모리 부족 경고같은 중요한 런타임 이벤트들을 delegate에게 알려서 대신 대응하도록 한다.

개발자가 직접 UIApplication을 상속받아서 사용할 필요는 없고 보통 미리 정의되어있는 AppDelegate 객체를 이용해서 시스템과 앱 간의 상호작용을 다룬다.

iOS 13 이후 바뀐점

iOS 12 이전에는 AppDelegate 만 사용하여 Process LifeCycle과 UILifeCycle 둘다 AppDelegate가 관리했으나,

iOS 13부터는

  • UI LifeCycle에 관해서는 SceneDelegate 가 관리하게 되었다.
  • 그러나 앱이 실행되고 종료되는 Process LifeCycle에 관해서는 AppDelegate 가 여전히 관리한다.
  • 따라서 역할이 분리되었지만, scene session이 생성되거나 삭제되는 Session LifeCycleAppDelegate 가 관리하게 되어 Scene에 관한 정보를 업데이트받는다.

그러니깐 다시말해서 앱 전반의 관리는 AppDelegate가, 거기에서 특정 scene의 라이프사이클은 SceneDelegate가 따로 관리한다는 뜻이다.

따라서 iOS 12까지는 하나의 앱에 하나의 window(창) 즉, 한 앱을 동시에 키는 것이 불가능하였지만

iOS 13부터는 window의 개념이 scene으로 대체되고 하나의 앱에서 여러 개의 scene을 가질 수 있게 되었다. 즉, 하나의 앱을 동시에 여러개 키는 것이 가능해졌다.

그렇다면 Scene이란 대체 무엇인가?

  • UI의 각 인스턴스를 나타내는 UIWindowView Controllers가 포함되어 있음
  • 각 scene에는 해당하는 UIWindowSceneDelegate 객체를 가지고 있음
  • 하나의 앱은 여러 scene과 해당 UIWindowSceneDelegate 객체를 동시에 활성화 가능

AppDelegate가 관리하게 된 Scene Session은 뭘까

UISceneSession 객체는 각 scene의 독립적인 런타임 인스턴스를 관리한다. 유저가 한 앱에 새로운 scene을 추가하게 되면 시스템은 UISceneSession 객체를 생성하여 그 scene을 관리하게 된다. 따라서 각 scene을 만들고 없애는 일련의 과정을 관리하는 것이다.

iOS 13부터 AppDelegate는 무슨 일을 할까

Session LifeCycle 과 Process LifeCycle
이 두가지를 관리하는 일을 하는데 전자에 관해서는 이전 질문에서 설명을 했으니 후자인 process에 관해 설명하겠다.

  • 앱의 중심적인 데이터 구조를 초기화하기
  • 앱 외부에서 발생하는 notification에 대응하기: 메모리 부족 워닝, 다운로드 완료 노티 등
  • 앱 전체를 타겟으로 하는 이벤트에 대응하기
  • 앱의 launch time에 필요한 서비스를 등록하는 일 ex) Apple Push Notification Service 등

App-Based / Scene-Based Life Cycle?

라이프 사이클과 각 단계로 전환되면서 호출되는 메서드들을 보기 쉽게 정리해놓은 이미지가 있어서 여기에서 가져왔다.

  • App Life Cycle

  • Scene Life Cycle

iOS 13부터 UI LifeCycle에 관해서는 SceneDelegate 가 관리하게 되었다고 했으니 Scene-Based Life-Cycle Events에 대해 자세히 알아보자.

Scene-Based Life-Cycle Events

Scene이란 디바이스에서 실행중인 앱의 UI의 인스턴스 중 하나이다. 단일 앱에 대해 여러 Scene을 생성할 수 있고 각각 독립적으로 화면에 띄우고, 숨길 수 있다. 각 Scene은 독립적인 Life Cycle을 가진다.

사용자나 시스템이 앱에 대한 새로운 scene을 요청하면, UIKit는 scene을 생성하여 unattatched 상태로 보낸다. 그리고 나서 사용자가 요청한 경우에는 foreground 상태로 변하지만, 시스템이 요청한 경우에는 background 상태로 보내진다.

사용자가 앱을 사용하다가 UI를 화면에서 없앴을때, UIKit는 scene을 background 상태로 보내고 결과적으로 suspended 상태로 보내게 된다.
그렇게 backgroundsuspended 상태에 있는 scene은 언제든지 연결이 끊겨서 unattatched 상태로 변할 수 있다.

각 state에 대해서 자세하게 알아보자면,
UIScene 클래스 안에 ActivationState 라는 Enum 타입을 가지고 있다.

extension UIScene {
    @available(iOS 13.0, *)
    public enum ActivationState : Int {
        case unattached = -1
        case foregroundActive = 0
        case foregroundInactive = 1
        case background = 2
    }
}
  • unattached
    • scene은 처음에 unattached 상태로 시작되며 시스템이 connection notification을 주기 전까지는 계속 이 상태를 유지한다.
  • foregroundActive
    • scene이 foreground에서 돌아가고 있으며, 현재 event들을 받고 있는 상태이다. active scene의 interface는 화면에 있으며 사용자에게 보여지게 된다.
  • forgroundInactive
    • scene이 foreground에서 돌아가고는 있지만 event를 받지는 않는다.
    • scene이 다른 상태로 전환되는 동안에 바로 이 foregroundInactive 상태를 통과하게 된다.
    • 예를 들면, 시스템 알람이 오거나 알람 창을 내리거나 app-switching을 하는 상황에서 이 상태가 된다.
  • background
    • scene이 스크린이 아닌 background에서 실행이 되고있는 상태이다.
    • background scene은 보여지는 interface가 없다.
  • suspended
    • 이 상태는 실제로 case 안에는 존재하지는 않는다.scene이 background 상태에 있으며, 아무것도 실행되지 않는 상태를 의미한다.

앱이 background와 foreground 상태에 있는 경우 제약사항이 있는지?

  • foreground에는 제약사항이 없고, 시스템 리소스에 우선권을 가진다.
  • background의 경우 메모리와 시스템 리소스에 대한 우선권을 박탈당한 상태이다.
    (아래의 상황 등 몇가지 예외사항 외에는 실행시간을 할당받지 못함)
    • Audio, AirPlay, PIP(Picture in Picture)
    • 사용자 위치 업데이트
    • Voice over IP
    • 외부 악세서리와의 통신
    • 블루투스 LE(Low Energy)와 통신, 혹은 디바이스를 블루투스 LE 악세서리로 변환
    • 서버에서의 정기적인 업데이트
    • RemoteNotification(Apple Push Notification 지원)
    • Background Processing

앱이 background에 있을 때 메모리에 올라와 있을지

  • 메모리에 올라가있고, 화면 밖에서 실행되고 있는 상태이다.

앱이 메모리에서 언제 완전히 해제될까

  • 메모리 확보, 사용자의 종료 등의 이유로 suspended 상태에서 not running상태로 이동할 때
  • applicationWillTerminate(_:) 메서드 이후

다음 상황에서의 App LifeCycle State는 어떻게 변할까

  • 실행 중인 앱을 멀티태스킹을 사용하여 Background로 보낸 뒤 다시 멀티태스킹을 사용하여 해당 앱으로 돌아왔을때

    • active -> inactive -> background -> inactive -> active
  • 실행 중인 앱을 멀티태스킹 창을 띄워 바로 종료하는 경우

  • 백그라운드 상태에 있는 앱을 종료하는 경우
    실험 결과 백그라운드에서 앱을 바로 종료하면 applicationWillTerminate 메서드가 불리지 않는다.

  • 실행 중인 앱을 바로 종료하는 경우
    그러나 실행 중인 앱을 바로 종료시 불린다.

그렇다면 중요한 데이터를 언제 저장하는 것이 좋을까

앱을 quit하는 상황(=> background로 전환하는 상황)에서 불리는 sceneWillResignActive에 저장하는 것이 좋을 것 같다.

왜냐하면 applicationWillTerminate(_:)의 경우 background를 지원하는 앱인 경우 background 상태에서 앱을 종료하면 불리지 않기 때문이다.

공식문서에도 앱을 deactivate하면 불리는 메서드인sceneWillResignActive에서 유저데이터를 저장하라고 한다.

Reference

https://developer.apple.com/documentation/uikit/uiapplication
https://developer.apple.com/documentation/uikit/uiapplicationdelegate
https://developer.apple.com/documentation/uikit/app_and_environment/scenes/preparing_your_ui_to_run_in_the_background
https://velog.io/@dev-lena/iOS-AppDelegate%EC%99%80-SceneDelegate
https://developer.apple.com/documentation/uikit/app_and_environment/managing_your_app_s_life_cycle

profile
제가 나중에 다시 보려고 기록합니다 ✏️

1개의 댓글

comment-user-thumbnail
2023년 3월 8일

정리 잘되어 있어서 잘보고 갑니다! 덕분에 도움이 많이 됐어요!!

답글 달기