티스토리 뷰

iOS

Application Life Cycle

cskime 2020. 7. 15. 11:31

이 글은 Github 블로그로 이전되면서 내용이 업데이트 되었습니다.


이번 글에서는 앱의 생명 주기에 대해 알아보려고 합니다. 이것도 ViewController의 생명 주기 만큼이나 중요한 내용이고, 면접 질문에 나올 확률도 꽤 될 것 같아서 한번 더 복습할 겸 정리했습니다. 글의 내용은 공식 문서를 읽고 요약한 것이므로 공식 문서도 함께 읽어보시면 도움이 됩니다.


App State?

앱의 생명 주기는 앱의 실행/종료 및 앱이 Foreground/Background 상태에 있을 때와 관련된 시스템이 발생시키는 event에 의해 앱의 상태가 전환되는 일련의 과정을 뜻합니다. 여기서 앱의 상태란 앱이 실행되고 있는지, 화면에 보여지고 있는지 등에 따라 표현되는 말그대로 앱의 상태를 의미합니다. 앱의 상태는 총 다섯 가지로 구분할 수 있습니다.

1. Not Running

 

Not Running은 앱이 아직 실행되지 않았거나, 완전히 종료되어 동작하지 않는 상태입니다.

 

2. Inactive

 

Inactive는 앱이 실행중이지만 사용자로부터 event를 받을 수 없는 상태입니다. 멀티태스킹 창으로 진입하거나 앱 실행 중 전화, 알림 등에 의해 앱을 사용할 수 없게 되는 경우 이 상태로 진입합니다.

 

3. Active

 

Active는 앱이 실제로 실행중이고 사용자 event를 받아 상호작용할 수 있는 상태입니다. 일반적으로 Active와 Inactive 상태를 통틀어 Foreground 상태라고 합니다. 앱은 Foreground와 Background 상태 사이를 이동할 때 반드시 Inactive 상태를 거칩니다.

 

4. Background

 

Background는 홈 화면으로 나가거나 다른 앱으로 전환되어 현재 앱이 실질적인 동작을 하지 않는 상태입니다. 음악 앱을 닫아도 재생한 음악이 계속 실행되는 경우를 생각해 볼 수 있습니다. 사용자가 앱을 사용하지 않는 동안 서버와 데이터를 동기화하거나 타이머가 실행되어야 하는 등의 작업을 이 상태에서 할 수 있습니다.

 

5. Suspended

 

Suspended는 앱을 다시 실행했을 때 최근 작업을 빠르게 로드하기 위해 메모리에 관련 데이터만 저장되어 있는 상태입니다. 앱이 Background 상태로 진입했을 때 다른 작업을 하지 않으면 Suspended 상태로 진입하게 됩니다 (보통 2~3초 이내로 전환된다고 합니다). 또, Suspended 상태의 앱들은 iOS가 메모리가 부족해지는 상황이 오면 가장 먼저 메모리에서 해제됩니다. 그럼 앱을 종료시킨 적이 없어도 다시 앱을 실행시키려고 하면 처음부터 다시 실행됩니다(리프레쉬 현상을 생각하면 됩니다).

Managing App's Life Cycle

우리는 앱의 상태를 전환시키는 시스템 Notification에 반응하여 현재 상태 변화에 대응되는 method를 통해 작업을 할 수 있습니다.

 

iOS 12 전까지는 전체 Life Cycle을 UIApplicationDelegate에서 관리하고 있었습니다. 그래서 해당 protocol을 채택하고 있는 AppDelegate에서 대응되는 method를 구현할 수 있었는데요. 하지만, iOS 13부터 Scene이라는 개념이 도입되면서 하나의 앱이 여러 UI Life Cycle을 가질 수 있게 되었습니다. 각각의 Scene에서 관리하는 UI Life Cycle은 UISceneDelegate에서 관리하고, 해당 protocol을 채택하고 있는 SceneDelegate가 각각의 Scene에서 관리하는 UI Life Cycle에 대응되는 method들을 구현하게 되었습니다.

 

정리하면, 앱 실행 및 종료와 관련된 Process Life Cycle은 AppDelegate에서, 앱이 Foreground와 Background 상태에 있을 때 상태 전환과 관련된 UI Life Cycle은 SceneDelegate에서 관리합니다. SceneDelegate를 사용하지 않도록 설정하면 예전처럼 AppDelegate가 모든 Life Cycle에 대한 관리 책임을 갖지만, 그렇지 않으면 UI Life Cycle은 SceneDelegate를 통해 관리해야 합니다.

Respond to App-Based Life Cycle

iOS 12 이전이고, Scene을 사용하지 않는다면 모든 Process/UI Life Cycle event들은 AppDelegate로 전달됩니다. 아래 그림은 AppDelegate에서 동작하는 전체 Life Cycle을 나타낸 것입니다.

1. 앱 실행: Not Running - Inactive - Active

 

앱이 실행되면 Not Running에서 Inactive를 거쳐 Active로 상태가 전환됩니다. 이 때, AppDelegate는 시스템에 다음 method를 호출하도록 요청합니다.

 

application(_:didFinishLaunchingWithOptions:)

앱이 실행되고 앱을 화면에 띄우기 위한 모든 설정이 완료된 뒤, 실제로 화면에 나타나기 직전에 호출됩니다. UIWindow를 생성하는 등의 작업을 할 수 있습니다. Storyboard를 사용한다면 storyboard에서 entry point를 찾아 내부적으로 UIWindow를 생성합니다.


applicationDidBecomeActive(_:)

앱이 Inactive에서 Active 상태로 전환되었을 때 호출됩니다.

 

2. To Background(offscreen): Active - Inactive - Background ( - Suspended)

 

앱 실행 후 홈 화면으로 나가면 Active에서 Inactive를 거쳐 Background로 상태가 전환됩니다. 이 때, AppDelegate는 시스템에 다음 method를 호출하도록 요청합니다.

 

applicationWillResignActive(_:)

앱이 Active에서 Inactive 상태로 전환될 때 호출됩니다.

 

applicationDidEnterBackground(_:)

앱이 Background 상태로 전환되었을 때 호출됩니다.

 

3. To Foreground(onscreen): Background - Inactive - Active

 

Background 상태에 있는 앱을 다시 실행하면 Inactive를 거쳐 Active 상태로 전환됩니다. 이 때, AppDelegate는 시스템에 다음 method를 호출하도록 요청합니다.

 

applicationWillEnterForeground(_:)

앱이 Background에서 Inactive 상태로 전환될 때 호출됩니다.

 

applicationDidBecomeActive(_:)

앱이 Inactive에서 Active 상태로 전환될 때 호출됩니다.

 

4. 앱 종료: (some States) - Background or Suspended - Not Running

 

사용자가 직접 앱을 종료시키는 경우, 앱은 다시 Not Running 상태로 돌아갑니다. 이 때, AppDelegate는 시스템에 다음 method를 호출하도록 요청합니다.

 

applicationWillTerminate(_:)

앱이 사용자에 의해 종료될 때 호출됩니다. 시스템에 의해 예기치 못한 상황에서 종료될 때는 호출되지 않습니다.

Respond to Scene-Based Life Cycle

iOS 13 이후의 앱에서 Scene을 사용한다면 각각의 분리된 Scene의 UI Life Cycle event들은 SceneDelegate로 전달됩니다. 아래 그림은 SceneDelegate에서 동작하는 UI Life Cycle을 나타낸 것입니다. (iOS 13에서도 Scene을 지원하지 않는다면 모든 event가 AppDelegate로 전달됩니다. 이 때는 App-Based Life Cycle로 동작합니다.)

1. 앱 실행

 

앱이 실행되면 앱을 화면에 보여주기 위한 모든 설정이 끝나고 다음 method가 호출됩니다.

 

application(_:didFinishLaunchingWithOptions:)

앱이 실행되고 앱을 화면에 띄우기 위한 모든 설정이 완료된 뒤, 실제로 화면에 나타나기 직전에 호출됩니다

 

2. Scene 연결

 

앱이 실행되면 UIKit에 Scene을 연결해야 합니다. Scene이 연결되고 화면에 나타나기까지 과정에서 다음 순서로 method들이 호출됩니다.

 

application(_:configurationForConnecting:options:)

새로운 Scene을 만들고 UIKit과 연결하기 위한 configuration을 지정합니다.

여기서 Configuration은 Scene의 delegation 객체를 지정하는 등 Scene을 연결하기 위한 정보가 들어 있는 UISceneConfiguration 객체를 말합니다. 일반적으로 info.plist에 추가된 기본값을 사용해서 생성합니다.

 

scene(_:willConnectTo:options:)

Scene이 연결될 것임을 delegate에 알려줍니다. 기존에 application(_:didFinishLaunchingWithOptions:)에서 했던 UIWindow 생성 작업을 이 method에서 할 수 있습니다. Storyboard를 사용한다면 storyboard에서 entry point를 찾아 내부적으로 UIWindow를 생성합니다.


sceneDidBecomeActive(_:)

앱이 Inactive에서 Active 상태로 전환되었을 때 호출됩니다.

 

3. To Background(offscreen): Active - Inactive - Background ( - Suspended)

 

앱 실행 후 홈 화면으로 나가면 Active에서 Inactive를 거쳐 Background로 상태가 전환됩니다. 이 때, SceneDelegate는 Scene에 다음 순서로 method를 호출하도록 요청합니다.

 

sceneWillResignActive(_:)

앱이 Active에서 Inactive 상태로 전환될 때 호출됩니다.

 

sceneDidEnterBackground(_:)

앱이 Background 상태로 전환되었을 때 호출됩니다.

 

4. To Foreground(onscreen): Background - Inactive - Active

 

Background 상태에 있는 앱을 다시 실행하면 Inactive를 거쳐 Active 상태로 전환됩니다. 이 때, SceneDelegate는 시스템에 다음 순서로 method를 호출하도록 요청합니다.

 

sceneWillEnterForeground(_:)

앱이 Background에서 Inactive 상태로 전환될 때 호출됩니다.

 

sceneDidBecomeActive(_:)

앱이 Inactive에서 Active 상태로 전환될 때 호출됩니다.

 

5. Scene 연결 해제

 

기존 App-Based Life Cycle에서는 멀티태스킹 창에서 swipe up 제스처를 사용하여 앱을 종료시켰습니다. 하지만 Scene을 사용할 때는 multi window를 지원하기 때문에, 앱이 둘 이상의 scene window를 갖는다면 swipe up 제스처는 앱을 종료시키지 않고 Scene을 해제시키게 됩니다. 만약 모든 Scene의 연결이 해제되었다면 앱이 종료됩니다.

 

Scene 연결이 해제될 때는 다음 순서로 method가 호출됩니다.

 

sceneDidDisconnected(_:)

delegate에 UIKit에 연결된 Scene의 연결을 해제할 것을 요청합니다.

 

application(_:didDiscardSceneSessions:)

사용자가 멀티태스킹 화면(app switcher)에서 한개 이상의 Scene을 종료시켰을 때 호출됩니다.

 

applicationWillTerminate(_:)

앱이 사용자에 의해 종료될 때 호출됩니다. 시스템에 의해 예기치 못한 상황에서 종료될 때는 호출되지 않습니다.

 

UI Life Cycle의 책임이 Scene으로 옮겨가면서, AppDelegate의 method 이름이 application에서 scene으로 바뀌기만 했을 뿐 맡은 역할과 호출되는 시점은 동일합니다.

 


 

앱 생명 주기를 잘 알아두면 앱을 사용하는 동안 일어날 수 있는 다양한 상황에 대응하여 작업을 처리할 수 있습니다. 직접 프로젝트를 만들어서 method가 호출되는 시점을 print로 찍어보면 도움이 됩니다 :)

'iOS' 카테고리의 다른 글

Frame과 Bounds의 차이  (0) 2020.08.07
GCD: Grand Central Dispatch  (0) 2020.07.27
Serial/Concurrent와 Sync/Async 이해하기(feat. DispatchQueue)  (0) 2020.07.26
Application Life Cycle  (0) 2020.07.15
ViewController Life Cycle  (0) 2020.07.13
PhotoKit 사용기  (0) 2020.07.12
댓글
댓글쓰기 폼