티스토리 뷰

iOS

ViewController Life Cycle

cskime 2020. 7. 13. 14:31

최근에 기술 면접을 봤는데 '뷰 컨트롤러 생명 주기에 대해서 얘기해보세요'라는 질문에 딱 떨어지게 대답할 수가 없었어요.. 잘 알고 있다고 생각해서 따로 공부하지도 않았는데 공부한지 시간이 많이 지나서 그런지 명확하게 설명이 잘 안되더라구요. 그래서 이번 글에서는 ViewController의 생명 주기에 대해 다시 한번 정리하는 시간을 가져보려고 합니다.

 

ViewController는 view와 관련해서 다양한 역할을 하고 있는데요. 이 내용을 모두 언급하기에는 생명 주기라는 글의 주제와 많이 벗어나는 것 같아서 이 글에서는 별도로 언급하지 않습니다. 하지만 아예 관련이 없는 것은 아니니 공식 문서를 꼭 읽어보시길 바랍니다.

 

그리고 다시 정리하는 김에, 화면이 전환되는 상황 별로 life cycle이 어떻게 달라지는지 다양하게 실험도 해봤습니다. 별 내용은 없지만 예제 프로젝트가 필요하신 분들은 여기에서 받으실 수 있습니다 :)

 

그럼 시작할게요!


생명 주기? Life Cycle?

iOS 개발을 처음 배울 때, 생명 주기라는 단어는 저에게 굉장히 추상적으로 다가왔던 것 같습니다. 어떤 강의나 글을 봐도 '어떤 함수가 어떤 순서로 실행된다'는 내용이 대부분이어서 '그래서 생명 주기가 뭔데?' 라는 의문이 해결되지 않았어요. 그래서, 생명 주기가 어떻게 되는지 알아보기 전에 먼저 생명 주기라는 단어의 명확한 정의를 내려보려고 합니다.

 

사전을 찾아보니 생명 주기라는 단어는 꽤 넓은 의미로 사용되고 있었습니다.

출처 : 네이버 사전

이 외에도 다양한 분야에서 생명 주기라는 단어를 사용하고 있는데, 공통적으로 시작부터 끝까지 일어나는 어떤 상태나 단계의 변화라는 의미를 나타냅니다.

 

그렇다면, ViewController의 생명 주기라는 것은 ViewController의 생성(initialize)부터 소멸(deinitialize)까지 변화하는 상태나 각 단계를 의미한다고 볼 수 있을 것입니다. 그리고 그 상태란, ViewController가 관리하는 view 계층(hierarchy)이 화면에 나타나고 사라지는 과정에서 view가 만들어 졌다, 나타났다, 사라졌다 같은 view의 상태를 의미합니다. 즉, ViewController의 생명 주기란 view가 화면에 나타나고 사라지는 일련의 상태 변화의 주기라는 뜻을 가지게 됩니다.

ViewController의 생명 주기

앱은 view를 화면에 나타내는 과정에서 특정 시점에 ViewController로 notification을 전달하는데, 이 notification이 전달되는 시점들이 ViewController의 생명 주기가 됩니다. 아래 그림은 ViewController가 받는 notification에 따라 변화하는 상태를 표현한 것입니다.

ViewController의 상태 변화는 ViewController가 맡은 역할에 따라 크게 둘로 나눠볼 수 있습니다.

1. View Management

ViewController가 생성되면 앱은 view를 생성해야 하는 시점에 loadView noti를 ViewController에 전달하고, ViewController는 view를 생성해서 root view로 할당합니다. Root view의 메모리 할당이 완료되면 ViewController는 viewDidLoad noti를 통해 메모리 할당이 완료되었음을 알림받습니다.

2. Handling View-Related Notifications

View hierarchy의 메모리 할당이 완료되면(viewDidLoad 후) ViewController는 view가 화면에 나타나기 시작하는 시점에 viewWillAppear noti를 받고, subview들을 생성하고 렌더링하는 과정을 거칩니다. 이 과정이 다 끝나면 viewDidAppear noti를 통해 화면에 view들이 모두 그려졌음을 알림받습니다.

 

그러다가, 화면 전환이 일어나면 현재 ViewController의 view는 사라지고 다른 ViewController의 view가 화면에 나타날 것입니다. 이 때, ViewController는 viewWillDisappear noti를 받고 현재 그려진 view들을 화면에서 없애는 작업을 거칩니다. 이 과정이 다 끝나면 viewDidDisappear noti를 통해 새로운 view가 화면에 나타나고 기존 view들이 화면에서 모두 사라졌음을 알림받습니다.

 

여기서 짚고 넘어가야 할 것은, View Management와 관련된 noti는 최초 ViewController가 view를 화면에 띄울 때 한 번만 발생하지만, 나머지 noti들은 view가 메모리에서 해제되기 전 까지 화면에 view들이 변화함에 따라 반복적으로 발생할 수 있다는 점입니다. 이런 특성을 활용하면 화면이 처음 나타날 때 한 번만 실행해야 하는 작업은 viewDidLoad noti를 받은 후에 실행한다거나, view가 화면에 나타날 때 마다 반복적으로 실행해야 하는 작업은 viewWillAppear 또는 viewDidAppear noti를 받은 후에 실행하는 등 작업의 목적에 따라 어떤 시점에 코드를 구현해야 할지 전략을 세울 수 있을 것입니다.

Responding Events

UIVIewController에는 특정 notification이 발생했을 때 호출되는 method들이 정의되어 있습니다. 우리는 해당 method들을 override해서 특정 시점에 동작해야 하는 코드를 실행시킬 수 있게 됩니다.

 

예제를 통해 두 개의 ViewController 사이에 화면 전환이 일어날 때 각각의 life cycle이 어떻게 동작하는지 로그를 찍어서 확인해보도록 하겠습니다. 대표적인 화면 전환 방법에는 present/dismiss를 사용한 modal 방식과 push/pop을 통한 navigation 방식이 있는데요. 각 방법마다 life cycle이 약간씩 다릅니다. 실제로 앱을 실행해서 하나씩 확인해 보도록 하죠.

1. Modal 방식 화면 전환 : Present/Dismiss

Modal 방식으로 화면을 전환할 때는 life cycle이 아래 이미지와 같이 동작하는 것을 확인할 수 있었습니다. 이미지는 PageA를 가리키고 있지만, 전체 과정을 보려고 PageB로 갔다가 다시 돌아온 상황입니다.

로그를 보면, 먼저 PageA가 화면에 나타나면서 loadView -> viewDidLoad -> viewWillAppear -> viewDidAppear 순으로 method가 호출되었습니다. View를 생성해서 메모리에 올린 뒤 화면에 그리는 순서대로 호출되었네요

 

Present가 찍힌 다음부터는 버튼을 눌러서 PageB로 전환될 때의 life cycle입니다. PageA는 화면에서 사라지고 PageB가 화면에 나타나기 때문에 양 쪽의 life cycle이 같이 동작합니다. 이 때, 두 life cycle이 동작하는 순서에 주의해야 합니다. PageB의 view를 만들어서 메모리에 할당한 뒤, PageB를 바로 화면에 띄우는게 아니라 PageA를 먼저 화면에서 내릴 준비를 하고 있습니다. 그 뒤에 pageB를 화면에 띄우는 작업을 시작하고, PageB가 완전히 화면에 나타난 뒤에야 비로소 PageA가 화면에서 완전히 내려갑니다.

 

Dismiss가 찍힌 다음부터는 PageB에서 다시 PageA로 돌아올 때의 Life cycle 입니다. 여기도 present할 때와 마찬가지로 PageA를 먼저 화면에 띄우지 않고 PageB를 먼저 화면에서 내릴 준비를 합니다. 

 

정리해 보면, Modal 방식의 화면 전환에서는

 

1. 현재 view를 내릴 준비를 하고

2. 새로운 화면을 띄운 다음에

3. 이전 view를 완전히 내리는

 

순서로 life cycle이 동작합니다.

2. Navigation 방식 화면 전환 : Push/Pop

Navigation 방식으로 화면을 전환할 때는 life cycle이 아래 이미지와 같이 동작합니다.

이번에는 PageC에서 PageD로 전환합니다. 최초 PageC가 화면에 나타나는 과정은 동일한데, Push와 Pop을 한 뒤에 life cycle에 순서가 modal 방식과 차이가 있었습니다. Modal 방식에서는 PageA에서 PageB로 전환될 때 PageB가 완전히 화면에 나타난 뒤에 PageA가 화면에서 완전히 내려갔는데, Navigation 방식에서는 PageD가 완전히 화면에 나타나기 전에 PageC가 화면에서 완전히 내려갔습니다.

 

즉, navigation 방식에서는

 

1. 현재 view를 내릴 준비를 하고

2. 새로운 화면을 띄울 준비를 한 다음에

3. 이전 view를 완전히 내리고

4. 새로운 view가 완전히 화면에 나타나는

 

순서로 life cycle이 동작하고 있습니다. 

 

각 경우에 life cycle을 도식으로 표현하면 이렇게 됩니다.

Modal 방식에서 life cycle과(왼쪽) navigation 방식에서 life cycle(오른쪽)

여기서 memory loaded를 체크하는 이유는 PageB에서 PageA로 돌아갈 때, PageA의 view는 화면에서 내려가기만 했을 뿐 메모리에는 그대로 살아있기 때문에 다시 Load할 필요가 없기 때문입니다.


지금까지 ViewController의 life cycle을 알아봤습니다. 글과 관련해서 잘못된 것이나 궁금한 점이 있다면 댓글로 남겨주세요!

'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
댓글
댓글쓰기 폼