UIViewController Life Cycle

Jayven·2024년 5월 15일
1

iOS

목록 보기
2/4
post-thumbnail

안녕하세요 제이븐입니다 😁

이번에 포스팅할 주제는 UIViewController의 생명주기입니다.

아래 순서대로 하나씩 알아보겠습니다.

  • UIViewController 생명 주기
  • UIViewController Life Cycle Method
  • 실습으로 생명주기 메서드 호출 시점 파악해보기

UIViewController Life Cycle


iOS에서는 스토리보드, Xib, CodeBase 세 가지 방식으로 ViewController를 생성할 수 있습니다.

위에 방법 중 어떤 방법으로 진행하던 ViewController가 생성되고 표시되고 소멸되는 Life Cycle을 제대로 이해야야지

사용자 인터페이스를 개선하고 제대로된 코드를 작성할 수 있습니다.


UIViewController Life Cycle Method

UIViewController의 생명주기 메서드와 그림

  • loadView()
  • loadViewIfNeeded()
  • viewDidLoad()
  • viewWillAppear(_ animated: Bool)
  • viewWillLayoutSubviews()
  • viewDidLayoutSubviews()
  • viewDidAppear(_ animated: Bool)
  • viewWillDisappear(_ animated: Bool)
  • viewDidDisappear(_ animated: Bool)

이미지 출처

loadView()

ViewController의 View가 처음으로 로드될 때 호출되며, ViewController의 Main View 프로퍼티를 생성하고 초기화하는 책임을 집니다.
기본적으로 loadView()는 StoryBoard나 nib 파일에서 뷰를 로드합니다. 그래서 StoryBoard, Xib를 사용하는 프로젝트에서는 직접 loadView 호출하는 것을 지양합니다.
하지만 CodeBase로 작업하는 경우에는 이 메서드를 오버라이드하여 직접 뷰를 생성하고 설정해야 됩니다.

사용시 주의해야될 점

  • StoryBoard, Xib 사용시 직접 호출하면 안됩니다.
    • ViewController의 View가 필요할 때 시스템이 알아서 loadView를 호출합니다.
    • CodeBase로 작업한다면 loadView에서 필요한 모든 뷰와 서브뷰를 직접 만들어서 뷰 계층을 구성해야 합니다.
  • Super 호출을 피하세요
    • loadView에서는 상위 클래스의 구현을 호출하면 안 되며, 대신 뷰 컨트롤러의 view 프로퍼티를 직접 인스턴스화해야 합니다.
  • 뷰 초기화
    • CodeBase로 작업할 경우 self.view에 새로운 UIView 인스턴스를 할당해야 합니다. 이는 ViewController의 메인 View 역할을 하게 됩니다.
  • 뷰 초기화 이외에 작업을 실행하면 안됩니다.
    • mainView를 할당하는 일 이외에 다른 뷰의 구성, 데이터 로딩, 뷰와 관련된 로직 실행은 viewDidLoad에서 실행해야됩니다.

loadViewIfNeeded()

ViewController의 View가 아직 메모리에 로드되지 않았을 때 이를 강제로 로드하는 역할을 합니다. CodeBase에서 View를 즉시 로드할 필요가 있을 때 사용됩니다.

loadViewIfNeeded() 메서드는 별다른 파라미터 없이 호출됩니다. ViewController 내부에서 뷰의 구성 요소를 설정하기 전에 뷰가 로드되었는지 확실하게 하고 싶을 때 사용할 수 있습니다.

func configure() {
	loadViewIfNeeded()
}

사용시 주의할 점

  • 불필요한 로드 방지

    • loadViewIfNeeded()를 호출하면 View 로딩이 강제로 진행되기 때문에, 필요하지 않은 상황에서 호출하면 메모리 사용이 비효율적일 수 있습니다. 뷰가 실제로 필요한 시점에만 호출해야 합니다.
  • 라이프사이클 메서드 중복 호출

    • loadViewIfNeeded()를 사용하면 loadViewviewDidLoad가 호출됩니다. 따라서 이 메서드를 호출하기 전에 이미 viewDidLoad에서 수행한 설정이 중복 실행되지 않도록 주의해야 합니다.
  • 성능 고려

    • 뷰 로딩은 비용이 많이 드는 작업이 될 수 있습니다. 뷰 컨트롤러의 뷰를 필요 이상으로 조기에 로드하는 것은 앱의 성능에 부정적인 영향을 미칠 수 있습니다. 특히 대량의 데이터 처리나 복잡한 뷰 구성이 이루어질 때는 더욱 주의해야 합니다.
      loadViewIfNeeded()는 특정 상황에서 뷰를 즉시 사용할 필요가 있을 때 유용하게 사용할 수 있지만, 이를 적절하고 효율적으로 사용하는 것이 중요합니다.

viewDidLoad()

ViewController가 뷰 계층 구조를 메모리에 로드한 후에 한 번만 호출되는 메서드입니다. 이 메서드는 뷰 계층 구조가 nib 파일에서 로드되었는지 또는 loadView() 메서드에서 프로그래밍 방식으로 생성되었는지에 관계없이 호출됩니다. 일반적으로 이 메서드를 재정의하여 nib 파일에서 로드된 뷰에 대한 추가 초기화를 수행합니다.

viewDidLoad가 호출되는 시점에서 뷰는 아직 화면에 표시되지는 않았지만, 모든 뷰 객체는 초기화되고 준비되어 있습니다.


viewDidLoad의 주요 역할

  • 초기 설정
    • 뷰와 관련된 초기 설정을 수행합니다. 예를 들어, 버튼에 액션을 연결하거나 레이블의 텍스트를 설정할 수 있습니다.
  • 데이터 로드
    • 뷰가 표시되기 전에 필요한 데이터를 로드하고 초기화할 수 있습니다.
  • 뷰 구성
    • 뷰 계층 구조가 메모리에 로드된 후에 뷰의 속성을 설정하거나 레이아웃을 조정할 수 있습니다.
  • UI 초기화
    • 스토리보드나 nib 파일에서 로드된 뷰에 추가로 초기화해야 할 부분을 설정할 수 있습니다.

viewWillAppear(_ animated: Bool)

ViewController의 뷰가 뷰 계층 구조에 추가되기 전과 뷰를 표시하기 위한 애니메이션이 구성되기 전에 호출됩니다. 이 메서드는 뷰가 화면에 나타날 때 마다 호출됩니다.


viewWillAppear의 주요 역할

  • 데이터 갱신
    • viewWillAppear는 뷰가 화면에 나타나기 직전에 호출되기 때문에, 이 메서드에서 최신 데이터를 로드하거나 기존 데이터를 갱신할 수 있습니다. 이는 사용자가 뷰를 볼 때 최신 정보를 제공할 수 있게 합니다.
  • 뷰 설정
    • 뷰의 설정을 갱신해야 할 경우, viewWillAppear에서 이를 처리할 수 있습니다. 예를 들어, 특정 조건에 따라 뷰의 일부 요소를 숨기거나 표시할 수 있습니다.
  • 애니메이션 준비
    • 화면에 나타나는 뷰에 대해 애니메이션을 준비하거나 설정할 수 있습니다. 예를 들어, 뷰가 나타날 때 페이드 인 효과를 주거나, 특정 UI 요소를 애니메이션으로 강조할 수 있습니다.
  • 상태 초기화
    • 뷰가 나타날 때마다 초기화해야 할 상태나 설정이 있다면, viewWillAppear에서 이를 수행할 수 있습니다.

사용 시 주의할 점

  • 빠른 실행
    • viewWillAppear는 뷰가 화면에 나타나기 직전에 호출되므로, 가능한 한 빠르게 실행되어야 합니다. 이 메서드에서 오래 걸리는 작업을 수행하면 뷰의 표시가 지연될 수 있습니다.
  • 상태 동기화
    • viewWillAppear에서 상태를 동기화할 때, 현재 상태를 정확하게 반영하도록 해야 합니다. 예를 들어, 데이터 모델의 변경 사항이 UI에 즉시 반영되도록 해야 합니다.
  • 애니메이션 사용 주의
    • viewWillAppear는 애니메이션 관련 작업을 준비하는 데 유용하지만, 실제 애니메이션은 viewDidAppear에서 수행하는 것이 더 적절합니다. 애니메이션을 준비할 때 viewWillAppear에서 설정을 하고, viewDidAppear에서 실제 애니메이션을 시작할 수 있습니다.

viewWillLayoutSubviews()

뷰가 서브뷰의 레이아웃을 조정하기 직전에 호출되는 메서드입니다.
이 메서드는 뷰의 bounds가 변경될 때마다 호출됩니다. 일반적으로 뷰의 배치나 레이아웃을 조정해야 할 때 사용됩니다.


viewWillLayoutSubviews 주요 역할

  • 레이아웃 조정 전 처리
    • 서브뷰의 레이아웃이 설정되기 전에 필요한 준비 작업을 수행합니다.
  • 커스텀 레이아웃 로직
    • 뷰의 서브뷰를 특정 방식으로 배치하거나 크기를 조정해야 할 때 커스텀 레이아웃 로직을 작성할 수 있습니다.

호출 시점

  • viewWillLayoutSubviews는 뷰의 레이아웃이 변경될 때마다 호출됩니다. 이는 뷰의 프레임이 변경되거나, 서브뷰가 추가되거나, 디바이스의 방향이 변경될 때 등을 포함합니다.
  • 뷰의 크기가 변경된 후, 서브뷰의 레이아웃을 다시 계산해야 할 때 호출됩니다.
  • 서브뷰의 레이아웃을 업데이트하기 직전에 호출됩니다.

호출 순서

  • viewWillLayoutSubviews는 뷰의 레이아웃이 변경될 때마다 호출됩니다.
  • 이 메서드는 view의 layoutSubviews 메서드가 호출되기 직전에 호출됩니다. layoutSubviews는 뷰가 실제로 서브뷰의 레이아웃을 설정하는 메서드입니다.
  • viewDidLayoutSubviewslayoutSubviews가 호출된 후에 호출됩니다.

viewDidLayoutSubviews()

뷰가 서브뷰의 레이아웃을 조정한 후에 호출되는 메서드입니다.
메서드는 뷰의 bounds가 변경될 때마다 호출되며, 레이아웃 작업이 완료된 후 후속 작업을 수행하는 데 사용됩니다.


viewDidLayoutSubviews 주요 역할

  • 레이아웃이 완료된 후 추가 작업을 수행합니다. 예를 들어, 레이아웃 후에 서브뷰의 특정 속성을 최종 조정하거나 애니메이션을 설정할 수 있습니다.

viewDidAppear(_ animated: Bool)

ViewController의 뷰가 화면에 완전히 표시된 후에 호출되는 메서드입니다.


viewDidAppear 주요 역할

  • 애니메이션 시작
    • 뷰가 화면에 완전히 나타난 후에 애니메이션을 시작할 수 있습니다. 예를 들어, 뷰 요소가 화면에 나타나는 애니메이션을 실행할 수 있습니다.
  • 데이터 로드 완료
    • 뷰가 나타난 후에 추가적인 데이터를 로드하거나 비동기 작업을 완료할 수 있습니다.

viewWillDisappear(_ animated: Bool)

ViewController의 뷰가 뷰 계층에서 제거되기 직전에 호출되는 메서드입니다.


viewWillDisappear 주요 역할

  • 데이터 저장
    • 사용자가 뷰를 떠나기 전에 데이터를 저장하거나 상태를 유지할 수 있습니다. 예를 들어, 사용자가 입력한 데이터를 저장하거나 변경된 설정을 저장할 수 있습니다.
  • 애니메이션 종료
    • 뷰가 사라지기 전에 실행 중인 애니메이션을 정리하거나 종료할 수 있습니다.

viewDidDisappear(_ animated: Bool)

ViewController의 뷰가 뷰 계층에서 제거된 후에 호출되는 메서드입니다.


viewDidDisappear 주요 역할

  • 상태 정리
    • 뷰가 완전히 사라진 후에 정리 작업을 수행할 수 있습니다. 예를 들어, 타이머를 중지하거나, 비동기 작업을 취소할 수 있습니다.
  • 리소스 해제
    • 더 이상 필요하지 않은 리소스를 해제하거나, 메모리를 정리할 수 있습니다.

실습


ViewController에서 Present, Push 등으로 새로운 화면이 나타나고 없어질 때 LifeCycle의 어떤 메서드가 호출되는지 알아보겠습니다.

MainView

메인 화면이 나타나면 아래 처럼 loadView -> viewDidLoad -> viewWillAppear -> viewDidAppear 이 불리는 것을 볼 수 있습니다.

A: loadView
A: viewDidLoad
A: viewWillAppear
A: viewDidAppear

Present

Present에도 pageSheet, fullScreen 등 화면을 전체로 덮으면서 올라오는 동작과 Main을 다 덮지 않고 올라오는 동작이 있고 이 두 동작이 A(Main)에 LifeCycle에 어떠한 영향을 끼치는지 하나 하나 보겠습니다

pageSheet

이 방식으로 새로운 B라는 ViewController가 올라가게 된다면 A(Main)은 DisAppear가 호출될까요?


답은 아닙니다 A(Main)에 영향을 주지않습니다 정확하게는 A(Main)의 DisAppear가 호출되지 않습니다.

A: loadView
A: viewDidLoad
A: viewWillAppear
A: viewDidAppear

B: loadView
B: viewDidLoad
B: viewWillAppear
B: viewDidAppear

그렇다면 이어서 아래처럼 B를 아래로 땡겼다가 다시 원래 위치로 돌리게 된다면 어떻게 될까요??

B를 아래로 당겨서 없애려는 순간 viewWillDisappear()가 호출되고 다시 되돌리면 viewWillAppear() -> viewDididAppear()가 호출됩니다.

당연히 뷰를 아예 제거한다면 viewDidDisAppear()이 호출될 것이고 A(Main)뷰는 DisAppear 된 적이 없기 때문에 LifeCycle 메서드를 호출하지 않을 것 입니다.

B: viewWillDisappear
B: viewWillAppear
B: viewDidAppear

fullScreen

그렇다면 위에와 다르게 fullScreen으로 A(Main)뷰를 덮는 화면을 띄우면 어떻게 될까요??

위에 동작과 다르게 B뷰가 로드되면 A(Main)은 WillDisAppear를 호출하고 B뷰가 DidAppear되는 순간 A(Main)뷰는 DidAppear를 호출합니다

B: loadView
B: viewDidLoad

A: viewWillDisappear

B: viewWillAppear
B: viewDidAppear

A: viewDidDisappear

BView를 종료하고 -> A(Main)으로 돌아가게 된다면
아래와 같이

  1. BView는 viewWillDisappear()를 호출합니다.
  2. A(Main)은 viewDidLoad() 이후의 viewWillAppear(), viewDididAppear()를 호출
  3. A(Main)가 viewDididAppear() 화면에 나타나면 뒤에 BView는 완전히 종료되면서 viewDidDisappear()를 호출합니다.
B: viewWillDisappear

A: viewWillAppear
A: viewDidAppear

B: viewDidDisappear

마지막으로 네비게이션의 push로 C뷰로 이동 했을 경우입니다

CView가 push되면서 나타낼때는 B뷰가 fullScreen으로 나타날때와 같습니다.

하지만 Back 버튼을 눌러서 pop하는 경우는 뭐가 다를까요??

코드를 보면 알다시피
1. viewWillDisappear가 호출됩니다.
2. A(Main)이 viewWillAppear()가 호출된 뒤
3. C에서 viewDidDisAppar()이 호출된 후에 A(Main)뷰가 DidAppear이 됩니다.

present와 다른 점은 A(Main)이 DidAppear된 후에 present된 뷰가 DisAppear이 되고
navigation은 C뷰가 DisAppear 이후에 A가 DidAppear된다는 점 입니다.

C: viewWillDisappear

A: viewWillAppear

C: viewDidDisappear

A: viewDidAppear

마무리


ViewController Life Cycle 그리고 호출되는 메서드에 대해서 포스팅 했습니다.

해당 라이프 사이클에 관련된 메서드들이 어떤 상황에서 호출되는지, 각 메서드에 어떤걸 넣어야되는지 다시 한 번 공부하는 시간이 였습니다

질문과 피드백은 언제나 환영입니다 🙇🙇

profile
iOS 개발자

0개의 댓글