오늘은 ViewController의 Lifecycle에 대해서 알아보도록 하겠다.
본문에 앞서 Lifecycle은
viewDidLoad(),
viewDidAppear(),
viewWillAppear(),
viewWillDisappear,
viewDidDisappear() 로 나뉜다.

우선 viewDidLoad()는 중요한 것이 view가 생성될 때, 단 한번만 load 된다.

그 다음으로 viewWillAppear()이 불러지는데, 이것은 view가 실제로 스크린에 보여지기 직전에 불러진다.
그래서 사용자는 아무것도 볼수 없는 상태이지만,
무언가를 hide하거나 특정한 UI components를 어떻게 설정하는 등 이 부분에서 설정하면 좋다.

그 다음은 viewDidAppear()가 불러진다.
viewDidAppear가 불러질 때에는 이미 유저들이 스크린을 볼 수 있는 상태이다.
그래서 여기서는 countdown counter를 실행하거나 animation을 나타내기에 좋다.

다음으로 viewWillDisappear()를 부를수 있다.
예를 들어 back navigate를 하거나 할 때, 이 method를 통해 준비를 미리 할 수 있다.
animation을 멈추거나 UI appearance를 바꾸고 싶을때 사용한다.

위 과정 다음으로는 viewDidDisappear()가 불러진다.
이것이 불러질 때에는 view는 스크린을 끌 준비가 되어있는 상태이다.
이 과정이 이전 view에 대한 것을 바꾸기 위한 마지막 순간이다.


코드를 통해 더욱 직관적으로 알아보자.
이 예시에서는 ViewController가 두가지 있고 코드는 아래와 같다.

// ViewController1.swift
import UIKit

class ViewController1: UIViewController {
    
    override func viewDidLoad() {
        super.viewDidLoad()
        print("VC1 viewDidLoad Called")
    }
    
    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        print("VC1 viewWillAppear Called")
    }
    
    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        print("VC1 viewDidAppear Called")
    }
    
    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
        print("VC1 viewWillDisappear Called")
    }
    
    override func viewDidDisappear(_ animated: Bool) {
        super.viewDidDisappear(animated)
        print("VC1 viewDidDisappear Called")
    }
}


// ViewController2.swift
import UIKit

class ViewController2: UIViewController {
    
    @IBOutlet weak var label: UILabel!
     
    @IBAction func goBack(_ sender: UIButton) {
        dismiss(animated: true, completion: nil)
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        label.text = "hello"
        
        print("VC2 viewDidLoad Called")
    }
    
    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        print("VC2 viewWillAppear Called")
    }
    
    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        print("VC2 viewDidAppear Called")
    }
    
    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
        print("VC2 viewWillDisappear Called")
    }
    
    override func viewDidDisappear(_ animated: Bool) {
        super.viewDidDisappear(animated)
        print("VC2 viewDidDisappear Called")
    }

}

앱을 실행하자마자 보이는 것이 아래와 같다.
VC1 viewDidLoad Called
VC1 viewWillAppear Called
VC1 viewDidAppear Called

그 다음으로 next 버튼을 눌러 다음 view를 불러오면, print되는 내용은 아래와 같다.
VC2 viewDidLoad Called
VC2 viewWillAppear Called
VC2 viewDidAppear Called

다시 back 버튼을 눌러 이전 view로 돌아가기를 하면, print되는 내용은 아래와 같다.
VC2 viewWillDisappear Called
VC2 viewDidDisappear Called

여기서 왜 viewDidDisappear, viewWillDisappear은 VC1에서 호출되지 않았을까?
지금 ViewController들의 segue가 카드 형식으로 가려져서 그런 것이다.
즉, 이전 VC1이 가려졌던 것이지 사실상 진짜로 사라지지 않았던 것이다.

여기서 VC2를 잡아 끌어내리기 시작하면, 그 순간 VC2 viewWillDisappear Called가 불러지고
다 내리면 VC2 viewDidDisappear Called가 불러진다.


그럼 카드형식으로 하지 않고, 완전히 가려지게 Present Modally / Full Screen으로 바꾸어 해보았다.
우선 VC1이 나에게 보이고 아래와 같은 코드가 출력되었다.
전과 마찬가지 였다.
앱을 실행하자마자 보이는 것이 아래와 같다.
VC1 viewDidLoad Called
VC1 viewWillAppear Called
VC1 viewDidAppear Called

그 다음으로 next 버튼을 눌러 다음 view를 불러오면, print되는 내용은 아래와 같다.
VC2 viewDidLoad Called
VC1 viewWillDisappear Called
VC2 viewWillAppear Called
VC2 viewDidAppear Called
VC1 viewDidDisappear Called
여기서 특이점은 VC1 이다.

다시 back 버튼을 눌러보면 아래와 같았다.
VC2 viewWillDisappear Called
VC1 viewWillAppear Called
VC1 viewDidAppear Called
VC2 viewDidDisappear Called

이러한 ViewController의 Lifecycle을 이해를 꼭 해야하는 이유가 예를 들어 무언가를 만들어 데이터를 할당하려고 하는데, 이러한 method를 잘못 써서 생성되기 전에 값을 할당을 하려해서 error가 뜬 경우가 나도 많았다.
이렇게 이해를 하였더라도 실제로 코드를 작성해보면 또 error가 뜰지 모르겠지만, 계속 의식을 하며 앞으로 코드를 작성해야겠다.

태그:

카테고리:

업데이트:

댓글남기기