생명 주기는 왜 알아야하고 중요할까?
iOS앱은 현재 상태에 따라서 할 수 있는 작업과 할 수 없는 작업이 결정된다.
Foreground 상태의 앱은 화면을 점유하며 사용자의 관심을 끌고 있기 때문에 시스템 자원에 있어서 우선권을 갖게 되고
Background 상태의 앱은 화면을 점유하지 않기 때문에 가능한 적게, 최소한의 작업을 해야한다.
따라서 개발자는 앱의 상태가 변화할 때마다 그에 맞는 동작을 적절하게 수행시킬줄 알아야 한다.
또 앱의 생명 주기를 알아야 개발할 수 있는 기능도 존재한다.
예를 들어 백그라운드 상태에서 노래나 동영상을 재생한다던가,
앱이 화면을 점유하고 있을 때만 타이머를 동작시키는 것 등이 있다.
이렇듯 앱의 생명 주기는 개발자라면 꼭 알아야 할 지식이다.
생명주기 - LifeCycle
생명주기(LifeCycle)는 앱의 최초 실행부터 앱이 완전히 종료되기 까지의 앱이 가지는 상태와 그 상태들 사이의 전이를 뜻한다.
App Based - ~ iOS 12
국내의 메가앱 및 대부분 iOS앱 모두 iOS 12 이하는 지원하지 않으므로, iOS 12까지의 생명주기는 간략하게 다루도록 하겠다.
(23.08.15 기준 카카오톡, 네이버 iOS 13.4 이상 지원 / 당근마켓, 배달의 민족 iOS 14.0 이상 지원)
iOS 12까지의 생명주기는 UIApplicationDelegate 객체를 통해서 생명 주기를 관리했다.
실제로 xCode에서 새로운 프로젝트를 생성하면 AppDelegate.swift 파일이 생성된다.
생명 주기 흐름도를 간단히 설명해보자면 위의 그림처럼 앱은 다섯가지의 상태를 가진다.
1️⃣ NotRunning
- 앱이 아직 실행되지 않았거나, 완전히 종료되어 동작하지 않는 상태
2️⃣ Inactive (Foreground)
- 앱이 실행되고 있어 Foreground에 있지만 이벤트를 받지 않는 상태
- Active 상태로 전이되기 전에 잠시동안 머무른다.
- 멀티태스킹 윈도우로 진입하거나 앱 실행 중 전화, 알림 등에 의해 앱을 사용할 수 없게 되는 경우에 해당한다.
3️⃣ Active (Foreground)
- 앱이 실행되고 있어 Foreground에 있고 이벤트가 발생한 상태
- 일반적으로 앱이 실행되는 상태
4️⃣ Running (Background)
- 앱이 Background 상태에 있으나 실행되는 코드가 있는 상태
- 뮤직 앱을 닫아도 음악이 계속 실행되는 경우, 사용자가 화면을 점유하고 있어야만 타이머가 동작하는 상태에 해당한다.
5️⃣ Suspended (Background)
- 앱이 Background 상태에 있으며 메모리에만 올라가 있고 코드를 실행하지 않는 상태
- Background에서 추가적인 작업이 없으면 자동으로 Suspended 상태로 전이된다.
- 다른 앱을 실행하면서 메모리가 부족해지면 iOS는 Suspended 상태에 있는 앱을 종료함으로써 메모리를 확보한다.
✅ UIApplicationDelegate
- 위의 상태들에 접근하기 위해 AppDelegate.swift 파일을 사용하여 접근한다.
- AppDelegate는 앱의 상태에 따라 실행되는 Delegate 메소드를 담고 있다
https://developer.apple.com/documentation/uikit/uiapplicationdelegate
ApplicationDelegate에 관해서는 iOS 공식문서에서 자세히 다루고 있으니 ~ iOS 12까지의 생명 주기는 여기까지 다루도록 하겠다.
Scene Based - iOS 13 ~
iOS 12 이전까지는 하나의 앱에 하나의 window를 가지고 있었고 AppDelegate 에서 앱의 생명 주기와 UI의 생명 주기를 모두 담당했었다. iOS 13 이후로 window의 개념이 scene으로 대체되었고 하나의 앱이 여러 scene을 가질 수 있게 되었다.
iOS 13 이후로 SceneDelegate가 추가되면서 UISceneDelegate가 앱의 생명 주기를 관리하게 되었고, App 단위의 상태 변화 관리에서 Scene 단위로 상태 변화를 관리하게 되었다.
✅ Scene
기기에서 실행 중인 앱 UI의 하나의 인스턴스를 의미한다.
- 하나의 앱에는 여러 개의 Scene 인스턴스가 존재할 수 있다.
- 하나의 Scene은 앱 인스턴스의 UI를 표현하기 위해 window와 viewController를 포함하고 각 인스턴스에 대응되는 UIWindowSceneDelegate 객체를 갖는다.
- 여러 Scene들은 동시적으로 실행되고 하나의 앱에서 같은 메모리와 프로세스 공간을 공유한다.
- 각 Scene은 고유의 생명 주기를 가지고 있기 때문에 서로 다른 실행 상태에 있을 수 있다. 예를 들어 하나의 Scene은 Foregound 상태에 올라와 있을 때, 나머지 Scene들은 Background 상태 또는 중지 상태일 수가 있다.
위의 그림은 Scene의 상태 전환을 보여주는 생명 주기 흐름도이다.
사용자나 시스템이 앱에 새로운 Scene을 요청하면 UIKit은 Scene을 생성하고 Unattached 상태로 둔다.
사용자가 요청한 Scene은 빠르게 Foreground 상태로 전이되어 화면에 출력된다.
시스템이 요청한 Scene은 보통 Background로 이동하여 이벤트를 처리한다. 예를 들어 시스템은 위치 이벤트를 처리할 Scene을 Background에서 실행하기도 한다.
사용자가 앱의 UI를 닫으면 UIKit은 관련된 Scene을 Background 상태로 전이시키고, 최종적으로는 중단 상태가 된다.
UIKit은 리소스 반환을 요구 받으면 언제든지 Background 또는 중단 된 Scene의 연결을 끊고 Unattached 상태로 되돌려놓을 수 있다.
✔️ UIKit이 Scene을 앱에 연결할 때 Scene의 최초 UI를 구성하고 Scene에 필요한 데이터를 불러온다
✔️ Forground-Active 상태로 전환될 때 UI를 구성하고 사용자와 상호작용 할 준비를 한다.
✔️ Forground-Active 상태에서 벗어나면 데이터를 저장하고 앱의 동작을 중단시킨다.
✔️ Background 상태에 진입 시 중요한 작업을 끝마치고, 되도록 많은 메모리리를 해제하고, 앱 스냅샷을 준비한다.
✔️ Scene의 연결이 끊기면 Scene과 관련 된 공유 리소스를 정리한다.
✔️ Scene과 관련된 이벤트 외에, 앱이 실행될 때에도 UIApplictionDelegate를 통해 응답해야한다.
1️⃣ Unttached
- Scene이 앱과 연결되어 있지 않은 상태
- Scene은 Unattached 상태에서 시작되며 시스템이 Scene에 연결 요청을 보낼 때까지 Unttached 상태로 유지된다.
2️⃣ Inactive (Foreground)
- 앱이 실행되고 있어 Foreground에 있지만 이벤트를 받지 않는 상태
- 다른 상태로 전이하는 동안 Inactive (Foreground) 상태를 지나간다.
- 시스템 알람, 제어센터 내리기, 앱 스위칭 등이 Inactive (Foreground) 상태에 해당된다.
3️⃣ Active (Foreground)
- 앱이 실행되고 있어 Foreground에 있고 이벤트가 발생한 상태
- 일반적으로 앱이 실행되는 상태
4️⃣ Running (Background)
- 앱이 Background 상태에 있으나 실행되는 코드가 있는 상태
- 뮤직 앱을 닫아도 음악이 계속 실행되는 경우, 사용자가 화면을 점유하고 있어야만 타이머가 동작하는 상태에 해당한다.
- 가능한 최소한의 동작을 수행해야하는 상황을 제외하면 아무것도 안하는 것이 제일 좋다.
5️⃣ Suspended (Background)
- 앱이 Background 상태에 있으며 메모리에만 올라가 있고 코드를 실행하지 않는 상태
- Background에서 추가적인 작업이 없으면 자동으로 Suspended 상태로 전이된다.
- 다른 앱을 실행하면서 메모리가 부족해지면 iOS는 Suspended 상태에 있는 앱을 종료함으로써 메모리를 확보한다.
✅ UISceneDelegate
- UISceneDelegate 객체를 사용해서 앱의 UI의 한 인스턴스에서 생명 주기 이벤트를 관리한다.
- UI의 상태에 따른 이벤트를 처리하기 위한 객체
1️⃣ Connecting and disconnecting the scene
optional func scene(
_ scene: UIScene,
willConnectTo session: UISceneSession,
options connectionOptions: UIScene.ConnectionOptions
)
scene(_:willConnectTo:options:)
- Scene이 앱에 추가될 때 호출되는 함수이다.
사용자 또는 앱이 UI의 새 인스턴스를 요청하면 UIKit이 적절한 Scene 객체를 만들어 앱에 연결한다.
이 방법을 이용하여 새로운 Scene 추가에 응답하고 Scene이 표시해야 하는 모든 데이터를 가져오기 시작한다.
❗️단, ViewController를 사용할 때 viewDidLoad()가 호출되는 단계는 아니다.
optional func sceneDidDisconnect(_ scene: UIScene)
sceneDidDisconnect(_:)
- Scene이 시스템에 의해 종료되었을 때 호출되는 함수이다.
- Scene이 메모리에서 제거되기 전에 최종적으로 정리를 수행한다.
2️⃣ Transitioning to the foreground
optional func sceneWillEnterForeground(_ scene: UIScene)
sceneWillEnterForeground(_:)
- Scene을 Foreground로 이동하기 전에 호출되는 함수이다.
- 새로 만든 Scene과 연결 된 Scene 모두에서 발생하며, Background에서 실행 중이고 시스템 또는 사용자의 작업에 의해 맨 앞으로 가져온 Scene에서도 발생한다.
❗️ Scene이 화면에 출력되기 전에 거치는 작업으로 Foreground로 전이되기 때문에 이 함수는 항상 sceneDidBecomeActvie(_:) 메소드를 호출한다.
optional func sceneDidBecomeActive(_ scene: UIScene)
sceneDidBecomeActive(_:)
- Scene이 Inactive 상태에서 Active로 상태로 전이되면 호출되는 함수이다.
- UIKit은 Scene에 대한 인터페이스를 로드한 후 해당 인터페이스가 화면에 나타나기 전에 이 메소드를 호출한다.
- View를 새로고침 하거나 타이머를 시작하거나, UI의 프레임 속도를 향상 시킬 때 이 메소드를 호출한다.
3️⃣ Transitioning to the background
optional func sceneWillResignActive(_ scene: UIScene)
sceneWillResignActive(_:)
- Scene이 Active 상태에서 Inactive 상태로 전이될 때 호출되는 함수이다.
- 일시적인 중단으로 인해 발생할 수 있다.
optional func sceneDidEnterBackground(_ scene: UIScene)
sceneDidEnterBackground(_:)
- Scene이 Foreground에서 Background로 전이될 때 호출되는 함수이다.
- Scene의 메모리 사용을 줄이고 공유 리소스를 확보하며 Scene의 UI를 정리할 수 있다.
- 이 메소드가 반환 된 직후 UIKit은 Scene 인터페이스의 스냅샷을 생성한다.
Reference
https://developer.apple.com/documentation/uikit/uiscenedelegate
https://developer.apple.com/documentation/uikit/uiapplicationdelegate
https://developer.apple.com/documentation/uikit/uiscene
https://developer.apple.com/documentation/uikit/app_and_environment/managing_your_app_s_life_cycle
https://developer.apple.com/videos/play/wwdc2019/258/
https://jeong9216.tistory.com/461
'iOS > iOS' 카테고리의 다른 글
[iOS] 생명주기 - ViewController LifeCycle 1 (0) | 2023.08.17 |
---|---|
[iOS] 생명주기 - iOS App LifeCycle 2 (1) | 2023.08.15 |
[iOS] 네트워크 통신 - URL, URLComponents (0) | 2023.08.12 |
[iOS] 네트워크 통신 - URLSession 간단한 예제 (0) | 2023.08.10 |
[iOS] 네트워크 통신 - URLSession (LifeCycle, GET/POST) (0) | 2023.08.10 |