생명주기
: 앱이 실행되는 동안 다양한 상태를 거치며 변화하는 것을 의미한다. 앱의 현재 상태에 따라 언제든지 앱이 수행할 수 있는 작업과 수행할 수 없는 작업을 결정하기에 이는 중요하다.
예를 들면 foreground app은 유저의 주목을 받기에 실행되는 기능들이 우선적으로 수행될 것이고, 반대로 background app은 최소한의 작업만을 수행할 것이다.(유저에게 보이지 않기때문에)
그렇기에 앱의 상태 변화에 따라서 적절한 동작을 수행할 수 있도록 조정하는 것이 사용자에게 더 나은 앱 환경을 제공할 것 같다.
IOS 13이전 app-based life cycle events
IOS 13이전에는 앱 기반 생명주기로 구성되어 있었다. UIKit에서는 UIApplicationDelegate가 모든 생명주기 events를 담당했다.
쉽게 말하자면, 앱의 상태변화(앱이 눈에 보이는 것, 안보이는 것 등)가 앱의 전체 UI에 영향을 미쳤다는 의미이다. 즉 디스플레이에 표시되는 콘텐츠를 포함하여 앱의 모든 화면과 인터페이스에 영향을 미치는 것이다.
앱 실행 후 시스템은 화면에 UI가 표시되는지에 따라 앱을 Inactive나 Background로 변경한다. Foreground 상태가 될 때 시스템은 앱을 자동적으로 Active로 변경한다. Background나 Suspended 상태에서는 메모리가 부족해지면 언제든지 Not Running 상태로 전환될 수 있다.
앱을 실행시키기 전은 그 어떠한 것도 시작되지 않았기에 Not Running상태이다.
- Not Running상태 : 아이폰의 어떤 영역도 차지하지 않는 상태
이후 앱을 실행하고자 클릭하면 inactive 상태나 background 상태가 된다.
- inactive : 앱이 화면에서 실행중이나 어떤 신호도 받지 않는 상태
- background : 앱이 화면에서 보이진 않지만 코드를 실행하고 있는 상태
UI가 화면에 나타날 준비가 되었는지 여부에 따라 준비가 되었다면 inactive, 되지 않았다면 background상태가 된다.
이후 앱의 상태는 inactive였을 경우, active상태가 되는데, 사용자의 상호작용과 시스템의 동작에 따라 active에서 background로 변하기도, background에서 active상태로 전환되기도 한다.
- active : 앱이 화면에서 실행중인 상태
IOS 13이전에는 하나의 앱만이 Active하게 동작할 수 있었다. 앱을 종료하면 Suspended상태로 들어가게 된다.
- Suspended : 앱이 곧 종료될 상태
IOS 13이후 scene-based life cycle events
App단위의 상태변화 관리에서 scene단위로 상태변화를 관리함. window라는 개념이 scene개념으로 바뀜.
더 이상 하나의 앱에 화나의 화면이라는 개념이 변하게 되었다. 두 개의 화면으로 분할해서 쓸 수 있는 것처럼 말이다. 이전에는 life cycle events를 모두 appdelegate에서 다뤘는데 이 기점으로 scene delegate가 등장하게 된다.
역할을 구분하자면 앱의 생명주기와 프로세스 이벤트는 여전히 appdelegate가 관리하지만, UI 생명주기는 새로운 scene delegate가 담당하게 된것이다.
scene이라는 개념이 등장하게 되는데, 한 개의 scene은 사용자가 기기에서 실행하는 앱의 UI를 나타내는 하나의 인스턴스를 말한다. 이전에는 하나의 앱이 하나의 인스턴스를 갖고 있었기에 앱이 실행중인 동안에는 하나의 UI만 사용할 수 있었다. 하지만 IOS13이후부터 multiple window를 지원하면서 하나의 앱이 여러개의 scene인스턴스를 가질 수 있게 되었다.
각 scene은 자체적으로 생명주기를 갖고 있다. 앱은 하나 이상의 scenedelegate를 가질 수 있게 구성되어 있다. 이를 통해 각 scene은 독립적으로 UI상태를 관리하고, 사용자에게 편리한 multiple window환경을 제공할 수 있게 된 것이다.
✅ Unattached : 앱이 실행되지 않은 상태(메모리에 올라오지 않은 상태), scene이 앱과 연결되어있지 않은 상태, scene은 Unattached상태에서 시작되며 시스템이 scene에 연결 알림을 보낼 때까지 해당 상태로 유지된다.
✅ Foreground : 화면을 점유하는 상태로, CPU를 포함한 시스템 리소스를 우선적으로 사용한다.
-〉 Inactive : 임시 비활성화 상태(전화나 알람등으로 인해 앱이 잠시 비활성화 되는 상태), 화면을 점유하지만 앱의 모든 동작을 사용자가 전부 컨트롤 할 수 없는 상황이면 Inactive상태이다, 외부적인 요인(Interrupt)에 의해 Inactive가 될 수 있다.
실행중이지만 이벤트를 수신하지 않는 상태, 다른 상태로 이동하는 동안 Foreground Inactive상태를 지나간다. Unattached → Foreground Active로 변경되는 사이와 Foreground Active → Background로 변경되는 사이에 Foreground Inactive가 배치된 것을 볼 수 있다.
시스템 알람, 제어센터 내리기, app-switching등이 예시이다.
- 〉 Active : 앱이 실행되고, 이벤트를 받을 수 있는 상태
✅ Background : 앱이 Background에 있거나, 스플릿 뷰 상에서 화면을 점유하지만 포커싱 되지 않은 상태, 제한적인 실행만가능하다.(음악재생, 사용자 위치사용 등), 백그라운드 상태에서 추가적인 작업이 없다면 Suspended상태로 이동한다.
실행중이지만 보이지 않는 것이 핵심내용이다.
최소한의 동작을 수행해야 하는데 아무것도 안하는게 가장 좋긴하다. 왜냐하면 특수한 음악재생 앱을 제외하면 메모리가 부족할 때 언제든지 Background 또는 Suspended연결을 끊어서 리소스를 회수하여 Unattached상태로 바꿀 수 있기 때문…(백그라운드 기능에 대한 심사도 엄격함…)
✅ Suspended : 앱이 일시 중단된 상태로, 다음 실행을 기다리는 대기 상태이다. 앱을 다시 실행할 경우 빠르게 실행하기 위해 메모리에만 올라가 있다. 메모리가 부족한 상황이 왔을 때 Suspended상태의 앱을 메모리에서 해제시켜 부족한 메모리를 확보한다.
앱이 background상태에서 추가적인 작업을 하지 않으면 이 단계로 진입한다. 앱을 다시 실행할 경우 빠른 실행을 위해 메모리에만 올라가 있다. 다만, 메모리가 부족할 때 언제든지 Unattached 상태가 될 수 있다.
유저가 사용중이던 앱의 UI를 dismiss하면(내리면) UIKit이 scene을 백그라운드로 이동시키고, 결국은 일시정지 상태로 보낸다. UIKit은 리소스를 회수하기 위해 언제든지 백그라운드 또는 일시중단된 scene의 연결을 끊고 해당 scene을 연결되지 않은 상태로 되돌릴 수 있다.
사용자나 시스템이 앱에 새로운 scene을 요청하게 되면, UIKit은 해당 scene을 만들어 Unattached상태로 변경시킨다.
이후 사용자가 요청한 scene은 실제 화면에 보이는 foreground로 움직인다. 반면 시스템이 요청한 scene은 일반적으로 background로 움직여 event를 처리한다.
사용자가 앱의 UI를 해제하면, UIKit은 scene을 Background상태로 옮기고, 결국 Suspended상태에 도달하게 된다.
UIKit은 Background나 Suspended된 scene을 언제든지 리소스들을 회수하기 위해 Unattached 상태로 연결을 해제할 수 있다. 이는 여러개의 scene들을 관리하면서 메모리효율을 위해 필요에 따라 scene과 관련된 리소스를 해제하는 과정이다.
Appdelegate에서는 UISceneSession Lifecycle에 대한 역할이 추가되었다.
아래 두 메서드는 Scene Session이 생성되거나 삭제될 때 Appdelegate에 알리기 위한 존재이다.
// MARK: UISceneSession Lifecycle
func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {
// Called when a new scene session is being created.
// Use this method to select a configuration to create the new scene with.
return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role)
}
func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set<UISceneSession>) {
// Called when the user discards a scene session.
// If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions.
// Use this method to release any resources that were specific to the discarded scenes, as they will not return.
}
새로운 Scene이 필요할 때마다 Appdelegate의 application(:configurationForConnecting:options:) -> UISceneConfiguration 가 호출되고, Scene이 추가되면 UISceneSession 라이프 사이클에서 scene(:willConnectTo:options:)가 호출된다.
IOS 13이후의 Appdelegate역할
- 앱의 중요한 데이터 구조를 초기화한다.
- Scene을 환경설정한다.
- 앱 밖에서 발생하는 알림에 대응한다.(배터리 부족, 전화수신)
- 특정 Scene, View, ViewController에 한정되지 않고, 앱 자체를 타깃으로 하는 이벤트에 대응한다.
- 애플 푸시 알림 서비스처럼 실행시 요구되는 모든 서비스를 등록한다.
SceneDelegate Method
Connecting and Disconnecting the Scene
- scene(:willConnectTo:options:)사용자 또는 앱이 사용자 인터페이스의 새 인스턴스를 요청하면 UIKit이 적절한 장면개체를 만들어 앱에 연결한다. 이 방법을 사용하여 새 씬 추가에 응답하고, 씬이 표시해야 하는 모든 데이터를 로드하기 시작한다.
- 단, 뷰 컨트롤러를 사용할때 viewDidLoad()가 호출되는 단계는 아니다.
- scene이 앱에 추가될 때 호출되는 함수이다.
- sceneDidDiscount(_:)
- scene이 시스템에 의해 종료되었을 대 호출된다. scene이 메모리에서 제거되기 전에 최종정리를 수행한다.
Transitioning to the Foreground
- sceneWillEnterForeground(_:)씬이 화면에 나타나기 위한 전조로 foreground에 들어가기 때문에 이 메서드는 항상 sceneDidBecomeActive(_:) 메서드를 호출한다.
- Scene을 forground로 이동하기 전에 호출된다. 새로만든 씬과 연결된 씬 모두에서 발생하며, 백그라운드에서 실행중이고 시스템 또는 사용자 작업에 의해 맨 앞으로 가져온 씬에서도 발생한다.
- sceneDidBecomeActive(_:)UIkit은 씬에 대한 인터페이스를 로드한 후, 해당 인터페이스가 화면에 나타나기 전에 이 메서드를 호출한다. view를 refresh하거나 타이머를 시작하거나 ui프레임 속도를 높일 때 이 메서드에 작성하면 된다.
- 씬이 inactive상태에서 active한 상태로 이동하면 호출된다.
Transitioning to the Background
- sceneWillResignActive(_:) Scene이 Active 상태에서 Inactive 상태로 이동할 때 호출된다. 이 메서드는 일시적인 중단(전화가 걸려올 때 등)으로 인해 발생할 수 있다.
- sceneDidEnterBackground(_:) Scene이 foreground에서 background로 전환될 때 호출된다. Scene의 메모리 사용을 줄이고 공유 리소스를 확보하며 Scene의 사용자 인터페이스를 정리할 수 있다. 이 메서드가 반환된 직후 UIKit은 앱 전환기에 표시할 씬(scene) 인터페이스의 스냅샷을 생성한다.
단계
- 앱 실행application(_: didFinishLaunchingWithOptions:)
- → 앱이 실행되고 앱을 화면에 띄우기 위한 모든 설정이 완료된 뒤, 실제로 화면에 나타나기 직전에 호출됨)
- 앱이 실행되면 앱을 화면에 보여주기 위한 모든 설정이 끝나고 다음 메서드가 호출된다.
- 씬 연결씬이 연결되고 화면에 나타나기 까지 다음의 순서대로 메소드들이 호출된다.→ 새로운 씬을 만들고 UIKit와 연결하기 위한 configuration을 지정, 여기서 configuration은 씬의 delegation객체를 지정하는 등 씬을 연결하기 위한 정보가 들어있는 UISceneConfiguration객체를 말한다. 일반적으로 info.plist에 추가된 기본값을 사용해서 생성한다.→ 씬이 연결될 것임을 delegate에 알려준다.sceneDidBecomeActive(_:)
- → 앱이 Inactive에서 Active상태로 전환되었을 때 호출된다.
- application(_: didFinishLaunchingWithOptions:)에서 했던 UIWindow생성작업을 이 메서드에서 할 수 있음. storyboard를 사용한다면 storyboard에서 엔트리 포인트를 찾아 내부적으로 UIWindow를 생성함.
- scene(_:willConnectTo:options: )
- application(:configurationForConnecting: options: )
- 앱이 실행되면 UIKit에 씬을 연결해야함
- 앱 실행 후 홈화면으로 나갔을 때이때, SceneDelegate는 Scene 다음의 순서대로 메서드들이 호출된다.→ 앱이 Active에서 Inactive상태로 전환될 때 소출된다.→ 앱이 백그라운드 상태로 전환되었을 때 호출된다.
- sceneDidEnterBackground(_:)
- sceneWillResignActive(_:)
- 앱 실행 후 홈화면으로 나가면 Active에서 Inactive를 거쳐 Background상태로 전환된다.
- 백그라운드에 있는 상태에서 앱을 다시 실행했을 때이 때, SceneDelegate는 시스템에 다음 메소드를 호출하도록 요청함→ 앱이 백그라운드에서 Inactive상태로 전환될 때 호출된다.→ 앱이 Inactive 상태에서 active상태로 전환될 때 호출된다.
- sceneDidBecomeActive(_:)
- sceneWillEnterForeground(_:)
- Background 상태에 있는 앱을 다시 실행하면 InActive를 거쳐 Active 상태로 전환됨.
- 씬 연결해제하지만 Scene을 사용할 때에는 Multi Window를 지원하기 때문에 앱이 둘 이상의 Scene Window를 가진다면, swift-up 제스처는 앱을 종료시키지 않고 Scene을 해제시키게 됨. 만약 모든 Scene의 연결이 해제되었다면 앱이 종료됨.sceneDidDisconnected(_:)application(_: didDiscardSceneSessions:)applicationWillTerminate(_:)
- → 앱이 사용자에 의해 종료될 때 호출된다. 시스템에 의해 예기치 못한 상황에서 종료될 때는 호출되지 않는다.
- → 사용자가 멀티태스킹 창에서 한개의 씬을 종료시켰을 대 호출된다.
- → delegate에 UIKit에 연결된 씬들의 연결을 해제할 것을 요청함
- Scene 연결이 해제될 때는 다음 순서로 메소드가 호출됨
- 기존 App-Based LifeCycle에서는 멀티태스킹 창(app Switcher)에서 swife-up 제스처를 사용해서 앱을 종료시켰음.
'개발일기 > IOS' 카테고리의 다른 글
[Swift] - CollectionView 정리 (0) | 2024.03.15 |
---|---|
[Swift] - ViewController 화면전환 (0) | 2024.03.15 |
[Swift] - ViewController 생명주기 (0) | 2024.03.15 |
[Swift] - View와 Layer 관계 (0) | 2024.03.15 |
[Swift] - Xcoordinator 정리해보자 (0) | 2024.03.15 |