[Swift] iOS 앱의 라이프 사이클 관리
오늘은 제가 iOS 앱의 라이프 사이클 관리에 대해 공부하기 위해 공식 문서를 참고하면서 정리한 부분을 포스팅하려고 합니다!
앱의 현재 상태란?
앱의 현재 상태에 따라 앱이 언제든지 수행할 수 있는 작업과 수행할 수 없는 작업을 결정
예를 들어, 포그라운드 앱은 사용자의 주의를 끌기 때문에 CPU를 비롯한 시스템 리소스보다 우선순위를 가집니다. 반면에 백그라운드 앱은 화면 밖에 있기 때문에 가능한 한 작업을 적게 수행해야 하며, 가급적 아무것도 수행하지 않는 것이 좋습니다.
앱의 상태가 변경되면 UIKit은 적절한 델리게이트 객체의 메서드를 호출하여 사용자에게 알립니다.
- iOS 13 이상: Scene 기반 앱의 생명 주기 이벤트에 응답하기 위해 UISceneDelegate 객체를 사용합니다.
- iOS 12 이전: UIApplicationDelegate 객체를 사용하여 생명 주기 이벤트에 응답합니다.
생명주기(Life Cycle)란?
앱의 최초 실행부터 앱이 완전히 종료되기 까지 앱이 가지는 상태와 그 상태들 사이의 전이를 생명주기라고 합니다.
앱의 상태는 앱이 현재 어떠한 것을 할 수 있는가를 결정합니다.
앱의 생명주기(App’s Life Cycle)란?
앱의 실행 / 종료 및 앱이 Foreground / Background에 있을 때, 시스템이 발생시키는 이벤트에 의해 앱의 상태가 전환되는 일련의 과정
앱의 상태(App state)
- NotRunning
- 앱이 아직 실행되지 않았거나, 완전히 종료되어 동작하지 않는 상태
- Foreground - Inactive
- Inactive는 앱이 실행중이지만 사용자로부터 이벤트를 받을 수 없는 상태. 멀티태스킹 윈도우로 진입하거나 앱 실행중 전화, 알림 등에 의해 앱을 사용할 수 없게 되는 경우 이 상태로 진입합니다.
- Foreground - Active
- Active는 앱이 실제 실행중이고 사용자 이벤트를 받아서 상호작용할 수 있는 상태이다. 바로 Active 상태는 될 수 없으며 Inactive 상태를 거쳐 Active 상태가 됩니다.
- Background - Running
- Background는 홈 화면으로 나가거나 다른 앱으로 전환되어 현재 앱이 실질적인 동작을 하지 않는 상태입니다.
- 예를 들어 뮤직 앱을 닫아도 재생한 음악이 계속 실행되는 경우, 사용자가 앱을 사용하지 않는 동안 서버와 데이터를 동기화 하거나 타이머가 실행되어야 하는 등의 작업을 이 상태에서 할 수 있습니다.
- Background -Suspended
- Suspended는 앱을 다시 실행했을 때 최근 작업을 빠르게 로드하기 위해서 메모리에 관련 데이터만 저장되어 있는 상태입니다.
- 앱이 Background 상태에 진입했을 때 다른 작업을 하지 않으면 Suspended 상태로 진입하게 됩니다. (보통 2-3초 이내)
앱의 생명주기 관리
Respond to Scene-Based Life Cycle
✔️iOS 13 버전 이상: Scene 사용
앱이 Scene을 지원하는 경우 UIKit은 각각의 Scene에 대해 별도의 생명 주기 이벤트를 제공합니다.
Scene은 기기에서 실행되는 앱 UI의 한 인스턴스를 나타냅니다. 사용자는 각 앱에 대해 여러 개의 Scene을 생성하고 이를 개별적으로 표시하거나 숨길 수 있습니다.
각 Scene은 고유한 생명 주기가 있으므로 각 장면은 서로 다른 실행 상태에 있을 수 있습니다.
예를 들어 한 Scene은 foreground에 있는 반면 다른 Scene은 background에 있거나 일시 중단된 상태(suspended)일 수 있습니다.
Scene의 상태 전환
위 그림은 Scene의 상태 전환을 보여줍니다.
사용자 또는 시스템이 앱에서 새 Scene을 요청하면 UIKit은 이를 생성하고 연결되지 않은 상태(Unattached)로 전환합니다. 사용자가 요청한 Scene은 빠르게 foreground로 이동하여 화면에 표시됩니다.
시스템 요청 Scene은 일반적으로 이벤트를 처리할 수 있도록 background로 이동합니다. 예를 들어, 시스템이 위치 이벤트를 처리하기 위해 background에서 Scene을 실행할 수 있습니다.
사용자가 앱의 UI를 종료하면 UIKit은 관련 Scene을 background 상태로 이동한 다음 일시 중단된(suspended) 상태로 전환합니다.
UIKit은 언제든지 background 또는 일시 중단된(suspended) Scene의 연결을 끊어 리소스를 회수하여 해당 Scene을 연결되지 않은 상태로 되돌릴 수 있습니다.
- 요약
- 사용자가 새 Scene 요청 → Scene 생성 후 연결되지 않은 상태(unattached)로 전환
- 사용자가 요청한 Scene은 빠르게 foreground로 이동하여 화면 표시
- 시스템 요청 Scene → 이벤트 처리를 위해 background에서 처리
- 사용자가 UI 종료 → 관련 Scene을 background로 이동 → 일시 중단된 상태 (suspended)로 전환
- 리소스 회수: background 또는 suspended Scene의 연결을 끊어서 리소스 회수 가능
- 사용자가 새 Scene 요청 → Scene 생성 후 연결되지 않은 상태(unattached)로 전환
1. 앱 실행
앱이 실행되면 앱을 화면에 보여주기 위해 모든 설정이 끝나고 다음 메서드가 호출됩니다.
application(_:didFinishLaunchingWithOptions:)
- 앱이 실행되고 앱을 화면에 띄우기 위한 모든 설정이 완료된 뒤, 실제로 화면에 나타나기 직전에 호출
2. Scene 연결
앱이 실행되면 UIKit에 Scene을 연결해야 합니다. Scene이 연결되고 화면에 나타나기까지 과정에서 다음과 같은 순서대로 메서드 들이 호출됩니다.
application(_:configurationForConnecting:options:)
여기서 Configuration은 Scene의 delegation 객체를 지정하는 등 Scene을 연결하기 위한 정보가 들어있는 UISceneConfiguration 객체를 의미합니다. 일반적으로 info.plist에 추가된 기본값을 사용해서 생성합니다.- 새로운 Scene을 만들고 UIKit과 연결하기 위한 configuration을 지정합니다.
scene(_:willConnectTo:options:)
- Scene이 연결될 것임을 delegate에 알려줍니다. 기존에
application(_:didFinishLaunchingWithOptions:)
에서 했던 UIWindow 생성 작업을 이 메서드에서 할 수 있습니다. 스토리보드를 사용한다면 스토리보드에서 entry point를 찾아 내부적으로 UIWindow를 생성합니다. sceneDidBecomeActive(_:)
- 앱이 Inactive 상태에서 Active 상태로 전환되었을 때 호출합니다.
3. To Background(offscreen): Active - Inactive - Background ( - Suspend)
앱 실행후 홈으로 나가게 되면 Active → Inactive → Background 상태로 상태가 전환됩니다. 이 때, SceneDelegate는 Scene에 다음 순서로 method를 호출하도록 요청합니다.
sceneWillResignActive(_:)
- 앱이 Active에서 Inactive 상태로 전환될 때 호출됩니다.
sceneDidEnterBackground(_:)
- 앱이 Background 상태로 전환되었을 때 호출합니다.
4. To Foreground(onscreen): Background - Inactive - Active
Background 상태에 있는 앱을 다시 실행하면 Background → Inactive → Active 상태로 전환됩니다. 이 때, SceneDelegate는 시스템에 다음 순서로 메서드를 호출하도록 요청합니다.
sceneWillEnterForeground(_:)
- 앱이 Background에서 Inactive 상태로 전환될 때 호출됩니다.
sceneDidBecomeActive(_:)
- 앱이 Inactive에서 Active 상태로 전환될 때 호출됩니다.
5. Scene 연결 해제
기존의 App-Based Life Cycle
은 멀티태스킹 창에서 swipe up 제스처를 사용하여 앱을 종료시켰습니다. 하지만 Scene을 사용할 때는 multi window를 지원하기 때문에, 앱이 둘 이상의 scene window를 가진다면 swipe up 제스처는 앱을 종료시키지 않고 Scene을 해제시키게 됩니다. 만약 모든 Scene의 연결이 해제된다면 앱이 종료됩니다.
Scene 연결이 해제될 때는 다음과 같은 순서로 메서드가 호출됩니다.
sceneDidDisconnected(_:)
- delegate에 UIKit에 연결된 Scene의 연결을 해제할 것을 요청합니다.
application(_:didDiscardSceneSessions:)
- 사용자가 멀티태스킹 화면(app switcher)에서 한 개 이상의 Scene을 종료시켰을 때 호출됩니다.
applicationWillTerminate(_:)
- 앱이 사용자에 의해 종료될 때 호출됩니다. 시스템에 의해 예기치 못한 상황에서 종료될 때는 호출되지 않습니다.
Respond to App-Based Life Cycle
iOS 12 이전 또는 Scene을 사용하지 않는다면 모든 Process / UI Life Cycle event는 AppDelegate로 전달됩니다.
1. 앱 실행: Not Running - Inactive - Active
앱이 실행되면 Not Running → Inactive → Active 로 상태가 전환됩니다. 이 때, AppDelegate는 시스템에 다음 메서드를 호출하도록 요청합니다.
application(_:didFinishLaunchingWithOptions:)
- 앱이 실행되고 앱을 화면에 띄우기 위한 모든 설정이 완료된 뒤, 실제로 화면에 나타나기 직전에 호출됩니다. UIWindow를 생성하는 등의 작업을 할 수 있습니다. Storyboard를 사용한다면 storyboard에서 entry point를 찾아 내부적으로 UIWindow를 생성합니다.
applicationDidBecomeActive(_:)
- 앱이 Inactive에서 Active 상태로 전환되었을 때 호출
2. To Background(offscreen): Active - Inactive - Background ( - Suspended)
앱 실행후 홈으로 나가게 되면 Active → Inactive → Background 상태로 상태가 전환됩니다. 이 때, AppDelegate는 Scene에 다음 순서로 method를 호출하도록 요청합니다.
applicationWillResignActive(_:)
- 앱이 Active에서 Inactive 상태로 전환될 때 호출됩니다.
앱이 Active에서 Inactive 상태로 전환될 때 호출됩니다.
applicationDidEnterBackground(_:)
- 앱이 Background 상태로 전환되었을 때 호출합니다.
3. To Foreground(onscreen): Background - Inactive - Active
Background 상태에 있는 앱을 다시 실행하면 Background → Inactive → Active 상태로 전환됩니다. 이 때, AppDelegate는 시스템에 다음 순서로 메서드를 호출하도록 요청합니다.
applicationWillEnterForeground(_:)
- 앱이 Background에서 Inactive 상태로 전환될 때 호출됩니다.
applicationDidBecomeActive(_:)
- 앱이 Inactive에서 Active 상태로 전환될 때 호출됩니다.
4. 앱 종료: (some States) - Background or Suspended - Not Running
사용자가 직접 앱을 종료하는 경우, 앱은 다시 Not Running 상태로 돌아갑니다. 이 때, AppDelegate는 시스템에 다음과 같은 메서드를 호출하도록 요청합니다.
applicationWillTerminate(_:)
- 앱이 사용자에 의해 종료될 때 호출됩니다. 시스템에 의해 예기치 못한 상황에서 종료될 때는 호출하지 않습니다.
Application vs. Scene
결국 두 방식의 차이점은 UI Life Cycle의 책임이 Scene으로 옮겨감의 차이입니다. AppDelegate의 메서드 이름이 application → scene으로 바뀌었을 뿐 호출 순서는 동일합니다.
Scene의 연결 유무의 차이가 존재하여 앱 실행후 scene 연결, 앱 종료는 scene은 scene 연결 해제를 먼저 해준다는 것의 차이가 존재합니다.